Project import
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..12c29fe
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,110 @@
+#
+#    Copyright (c) 2010-2011 Nest, Inc.
+#    All rights reserved.
+#
+#    This document is the property of Nest. It is considered
+#    confidential and proprietary information.
+#
+#    This document may not be reproduced or transmitted in any form,
+#    in whole or in part, without the express written permission of
+#    Nest.
+#
+#    Description:
+#      This file is the makefile for c-kermit, a combined serial and
+#      network communication software package.
+#
+
+BuildConfigSpecialized	:= No
+BuildProductSpecialized	:= No
+
+include pre.mak
+
+PackageName		:= ckermit
+
+PackageExtension	:= tar.gz
+PackageSeparator	:= -
+
+PackagePatchArgs	:=
+
+PackageArchive		:= $(PackageName).$(PackageExtension)
+PackageSourceDir	:= $(PackageName)$(PackageSeparator)$(PackageVersion)
+
+PackageBuildMakefile	= $(call GenerateBuildPaths,makefile)
+
+CleanPaths		+= $(PackageLicenseFile)
+
+NCursesDir		:= sw/tps/ncurses
+NCursesIncDir		:= $(call GenerateResultPaths,$(NCursesDir),usr/include)
+NCursesLibDir		:= $(call GenerateResultPaths,$(NCursesDir),usr/lib)
+
+all: $(PackageDefaultGoal)
+
+# Generate the package license contents.
+
+$(PackageSourceDir)/COPYING.TXT: source
+
+$(PackageLicenseFile): $(PackageSourceDir)/COPYING.TXT
+	$(copy-result)
+
+# Extract the source from the archive and apply patches, if any.
+
+$(PackageSourceDir): $(PackageArchive) $(PackagePatchPaths)
+	$(create-directory)
+	$(call expand-archive,$(PackageArchive),$(@))
+	$(Verbose)touch $(@)
+	$(call patch-directory,$(@),$(PackagePatchArgs),$(PackagePatchPaths))
+
+# Prepare the sources.
+
+.PHONY: source
+source: | $(PackageSourceDir)
+
+# Patch the sources, if necessary.
+
+.PHONY: patch
+patch: source
+
+# Generate the package build makefile.
+
+$(PackageBuildMakefile): | $(PackageSourceDir) $(BuildDirectory)
+	$(call create-links,$(CURDIR)/$(PackageSourceDir),$(BuildDirectory))
+
+# Configure the source for building.
+
+.PHONY: configure
+configure: source $(PackageBuildMakefile)
+
+# Build the source.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+.PHONY: build
+build: configure
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+	INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	CC="$(CC)" CXX="$(CXX)" AR=$(AR) NM=$(NM) RANLIB=$(RANLIB) STRIP=$(STRIP) \
+	NCURSES_CPPFLAGS=$(call ToolGenerateIncludeArgument,$(NCursesIncDir)) \
+	NCURSES_LDFLAGS=$(call ToolGenerateLibraryPathArgument,$(NCursesLibDir)) \
+	linux-cross
+
+# Stage the build to a temporary installation area.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+.PHONY: stage
+stage: build | $(ResultDirectory)
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+	INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	DESTDIR=$(ResultDirectory) \
+	prefix=/usr \
+	MANDIR="" \
+	install
+
+clean:
+	$(Verbose)$(RM) $(RMFLAGS) -r $(PackageSourceDir)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(BuildDirectory)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(ResultDirectory)
+
+include post.mak
diff --git a/ckermit-8.0.211/COPYING.TXT b/ckermit-8.0.211/COPYING.TXT
new file mode 100644
index 0000000..da5d39e
--- /dev/null
+++ b/ckermit-8.0.211/COPYING.TXT
@@ -0,0 +1,106 @@
+THE C-KERMIT 7.0 AND 8.0 LICENSE
+
+  Last update: Thu May  1 13:52:15 2003
+
+This is the new C-Kermit 7.0 and 8.0 license.  The intention is to allow
+C-Kermit to be distributed with "free" operating systems such as GNU/Linux,
+FreeBSD, NetBSD, OpenBSD, The Hurd, etc, even when the distributions
+themselves (such as Red Hat or Caldera) might be sold and/or might include
+applications that are not free, and yet still require a license to include
+C-Kermit in or with "non-free" products such as commercial OS's, commercial
+software packages, embedded systems, and hardware (other than general-purpose
+computers preloaded with "free" operating systems), since these licenses
+furnish a large portion of the Kermit Project's funding.
+
+There have been some questions about the provision in Clause (A) that:
+
+                                                                  The
+    C-Kermit source code may not be changed without the consent of the
+    Kermit Project, which will not be unreasonably withheld (this is
+    simply a matter of keeping a consistent and supportable code base).
+
+The intention of this clause is primarily to make sure that anybody who
+makes modifications sends them back to us, since we are the ones have to
+support C-Kermit, and so we can carry them through to future releases (so
+you don't have to make the same changes again and again).
+
+Secondarily it is to protect Columbia University in the unlikely event of
+modifications made with deliberate intent to offend or cause damage.
+
+Any redistributor of C-Kermit under Clause (A) below should rest assured
+there is no intention of preventing them from constructing a distribution in
+the appropriate format (RPM or whatever) for their product or from issuing
+any patches required for their products; we simply want to be informed so we
+can maintain a consistent code base and a solid, supportable software
+package.  We are happy to work with any redistributor an any issues that
+concern them.  If you have questions, send them to kermit@columbia.edu.
+
+Note: All changes to this file since 1 January 2000 (the C-Kermit 7.0
+release date) are above; the license itself has not changed, except to
+update the most recent copyright date.
+
+(Begin)
+
+Copyright (C) 1985, 2003,
+  The Trustees of Columbia University in the City of New York.
+  All rights reserved.
+
+PERMISSIONS:
+
+The C-Kermit software may be obtained directly from the Kermit Project at
+Columbia University (or from any source explicitly licensed by the Kermit
+Project or implicitly licensed by Clause (A) below) by any individual for
+his or her OWN USE, and by any company or other organization for its own
+INTERNAL DISTRIBUTION and use, including installation on servers that are
+accessed by customers or clients, WITHOUT EXPLICIT LICENSE.
+
+Conditions for REDISTRIBUTION are as follows:
+
+(A) The C-Kermit software, in source and/or binary form, may be
+    included WITHOUT EXPLICIT LICENSE in distributions of OPERATING
+    SYSTEMS that have OSI (Open Source Initiative, www.opensource.org)
+    approved licenses, even if non-Open-Source applications (but not
+    operating systems) are included in the same distribution.  Such
+    distributions include, but are not limited to, CD-ROM, FTP site,
+    Web site, or preinstalled software on a new GENERAL-PURPOSE
+    computer, as long as the primary character of the distribution is
+    an Open Source operating system with accompanying utilities.  The
+    C-Kermit source code may not be changed without the consent of the
+    Kermit Project, which will not be unreasonably withheld (this is
+    simply a matter of keeping a consistent and supportable code base).
+
+(B) Inclusion of C-Kermit software in whole or in part, in any form, in
+    or with any product not covered by Clause (A), or its distribution
+    by any commercial enterprise to its actual or potential customers
+    or clients except as in Clause (A), requires a license from the
+    Kermit Project, Columbia University; contact kermit@columbia.edu.
+
+The name of Columbia University may not be used to endorse or promote
+products derived from or including the C-Kermit software without specific
+prior written permission.
+
+DISCLAIMER:
+
+  THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
+  TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK AS TO ITS
+  FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE TRUSTEES OF
+  COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK OF ANY KIND, EITHER
+  EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+  THE TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK SHALL NOT
+  BE LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL,
+  OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR
+  IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS
+  HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  YOU SHALL
+  INDEMNIFY AND HOLD HARMLESS THE TRUSTEES OF COLUMBIA UNIVERSITY IN
+  THE CITY OF NEW YORK, ITS EMPLOYEES AND AGENTS FROM AND AGAINST ANY
+  AND ALL CLAIMS, DEMANDS, LOSS, DAMAGE OR EXPENSE (INCLUDING
+  ATTORNEYS' FEES) ARISING OUT OF YOUR USE OF THIS SOFTWARE.
+
+The above copyright notice, permissions notice, and disclaimer may not be
+removed, altered, or obscured and shall be included in all copies of the
+C-Kermit software.  The Trustees of Columbia University in the City of
+New York reserve the right to revoke this permission if any of the terms
+of use set forth above are breached.
+
+(End)
diff --git a/ckermit-8.0.211/ck_crp.c b/ckermit-8.0.211/ck_crp.c
new file mode 100644
index 0000000..c35afd0
--- /dev/null
+++ b/ckermit-8.0.211/ck_crp.c
@@ -0,0 +1,5590 @@
+char *ckcrpv = "Encryption Engine, 8.0.114,  9 Oct 2003";
+/*
+  C K _ C R P . C  -  Cryptography for C-Kermit"
+
+  Copyright (C) 1998, 2004,
+    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 <krb5.h>
+#endif /* MIT_CURRENT */
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef OS2
+#include <stdarg.h>
+#ifdef OS2ONLY
+#include <os2.h>
+#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 CRYPT_DLL
+int cmd_quoting = 0;
+
+#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 *,long)=NULL;
+static int (*p_dohexdump)(char *,char *,int)=NULL;
+static void (*p_tn_debug)(char *)=NULL;
+static int (*p_vscrnprintf)(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, long 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_vscrnprintf )
+        return(p_vscrnprintf(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
+#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 <openssl/des.h>
+#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<NUM_WEAK_KEY; i++) {
+        /* Added == 0 to comparision, I obviously don't run
+        * this section very often :-(, thanks to
+        * engineering@MorningStar.Com for the fix
+        * eay 93/06/29
+        * Another problem, I was comparing only the first 4
+        * bytes, 97/03/18 */
+        if (memcmp(weak_keys[i],key,sizeof(Block)) == 0)
+            return(1);
+    }
+    return(0);
+}
+
+#ifdef UNIX
+#ifdef LIBDES
+/* These functions are not part of Eric Young's DES library */
+/* _unix_time_gmt_unixsec                                  */
+/* _des_set_random_generator_seed                          */
+/* _des_fixup_key_parity   (added in 0.9.5)                */
+/* _des_new_random_key                                     */
+#include <sys/time.h>
+
+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;
+    rc = des_random_key(B);
+    return(rc);
+}
+
+#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 <stdio.h>
+
+/*
+ * These function pointers point to the current routines
+ * for encrypting and decrypting data.
+ */
+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
+
+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
+    hexdump("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<str_suplen-2;i++ ) {
+            if ( str_send[i] == IAC ) {
+                ckstrncat(tn_msg,"IAC ",TN_MSG_LEN);
+                i++;
+            }
+            ckstrncat(tn_msg,ENCTYPE_NAME(str_send[i]),TN_MSG_LEN);
+            ckstrncat(tn_msg," ",TN_MSG_LEN);
+        }
+        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_send, str_suplen);
+#ifdef OS2
+    ReleaseTelnetMutex();
+#endif
+
+    str_suplen = 0;
+}
+
+/*
+ * Called when ENCRYPT SUPPORT is received.
+ */
+int
+#ifdef CK_ANSIC
+encrypt_support(unsigned char *_typelist, int _cnt)
+#else
+encrypt_support(_typelist, _cnt) unsigned char * _typelist; int _cnt;
+#endif
+{
+    register int type, use_type = 0;
+    unsigned char * typelist = _typelist;
+    int cnt = _cnt;
+    Encryptions *ep;
+
+    debug(F111,"encrypt_support","cnt",cnt);
+
+  /*
+   * Forget anything the other side has previously told us.
+   */
+    remote_supports_decrypt = 0;
+
+    while (cnt-- > 0) {
+        type = *typelist++;
+        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;
+            }
+        }
+    }
+    if (use_type) {
+        ep = findencryption(use_type);
+        if (!ep) {
+            debug(F111,"encrypt_support","findencryption == NULL",use_type);
+            return(-1);
+        }
+        type = ep->start ? (*ep->start)(DIR_ENCRYPT, 0) : 0;
+#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(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(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(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(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(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(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(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));
+    hexdump("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);
+    }
+
+    hexdump("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));
+
+    hexdump("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);
+    }
+    hexdump("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));
+
+    hexdump("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);
+    }
+    hexdump("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(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(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(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(buf,"Can't set 3DES session key (%d < %d)",
+                key ? key->length : 0, 2 * 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;
+    }
+    hexdump("des3_session_key key->data",key->data,sizeof(Block));
+    hexdump("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);
+        }
+        hexdump("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));
+
+        hexdump("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);
+        }
+        hexdump("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));
+
+        hexdump("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);
+        }
+        hexdump("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 <stdio.h>
+#ifdef  __STDC__
+#include <stdlib.h>
+#endif
+
+/*
+ * 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 */
+
+extern encrypt_debug_mode;
+
+#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(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( struct _crypt_dll_init * init )
+{
+#ifdef LIBDES
+    extern int des_check_key;
+    extern void libdes_dll_init(struct _crypt_dll_init *);
+    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_vscrnprintf = init->p_vscrnprintf;
+        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->p_install_funcs("encrypt_parse",encrypt_parse);
+        init->p_install_funcs("encrypt_init",encrypt_init);
+        init->p_install_funcs("encrypt_session_key",encrypt_session_key);
+        init->p_install_funcs("encrypt_send_request_start",
+                              encrypt_send_request_start
+                              );
+        init->p_install_funcs("encrypt_request_start",encrypt_request_start);
+        init->p_install_funcs("encrypt_send_request_end",
+                              encrypt_send_request_end
+                              );
+        init->p_install_funcs("encrypt_request_end",encrypt_request_end);
+        init->p_install_funcs("encrypt_send_end",encrypt_send_end);
+        init->p_install_funcs("encrypt_send_support",encrypt_send_support);
+        init->p_install_funcs("encrypt_is_encrypting",encrypt_is_encrypting);
+        init->p_install_funcs("encrypt_is_decrypting",encrypt_is_decrypting);
+        init->p_install_funcs("get_crypt_table",get_crypt_table);
+        init->p_install_funcs("des_is_weak_key",ck_des_is_weak_key);
+        libdes_dll_init(init);
+        if (init->version == 3)
+          return(1);
+    }
+    if ( init->version >= 4 ) {
+        init->p_install_funcs("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->p_install_funcs("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 */
diff --git a/ckermit-8.0.211/ck_des.c b/ckermit-8.0.211/ck_des.c
new file mode 100644
index 0000000..c534652
--- /dev/null
+++ b/ckermit-8.0.211/ck_des.c
@@ -0,0 +1,98 @@
+/*
+  C K _ D E S . C  -  libDES interface for Kermit 95"
+
+  Copyright (C) 1998, 2001, 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)
+*/
+
+/*
+   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 NT
+#ifdef _M_ALPHA
+#include <c:\srp\des\des.h>
+#else
+#include <c:\src\srp\des\des.h>
+#endif
+#else
+#include <c:\srp\des\des.h>
+#endif
+
+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);
+}
+
+void
+libdes_dll_init(struct _crypt_dll_init * init)
+{
+    init->p_install_funcs("libdes_random_key",libdes_random_key);
+    init->p_install_funcs("libdes_random_seed",libdes_random_seed);
+    init->p_install_funcs("libdes_key_sched",libdes_key_sched);
+    init->p_install_funcs("libdes_ecb_encrypt",libdes_ecb_encrypt);
+    init->p_install_funcs("libdes_string_to_key",libdes_string_to_key);
+    init->p_install_funcs("libdes_fixup_key_parity",libdes_fixup_key_parity);
+    init->p_install_funcs("libdes_pcbc_encrypt",libdes_pcbc_encrypt);
+
+}
+#endif /* LIBDES */
diff --git a/ckermit-8.0.211/ck_ssl.c b/ckermit-8.0.211/ck_ssl.c
new file mode 100644
index 0000000..7b53770
--- /dev/null
+++ b/ckermit-8.0.211/ck_ssl.c
@@ -0,0 +1,4242 @@
+char *cksslv = "SSL/TLS support, 8.0.221, 26 Feb 2004";
+/*
+  C K _ S S L . C --  OpenSSL Interface for C-Kermit
+
+  Copyright (C) 1985, 2004,
+    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
+
+  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.
+  It will also compile with version 0.9.5 although that is discouraged
+  due to security weaknesses in that release.
+*/
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+
+#ifdef CK_SSL
+#include "ckcnet.h"
+#include "ckuath.h"
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef UNIX
+#include <netinet/in.h>
+#ifndef FREEBSD4
+#include <arpa/inet.h>
+#endif /* FREEBSD4 */
+#endif /* UNIX */
+
+#ifdef DEC_TCPIP
+#include <time.h>
+#include <inet.h>
+#endif /* DEC_TCPIP */
+
+#ifdef OS2
+extern char exedir[];
+#ifdef NT
+char * GetAppData(int);
+#endif
+#endif /* OS2 */
+
+static int ssl_installed = 1;
+#endif /* CK_SSL */
+int
+ck_ssh_is_installed()
+{
+#ifdef SSHBUILTIN
+#ifdef SSLDLL
+#ifdef NT
+    extern HINSTANCE hCRYPTO;
+#else /* NT */
+    extern HMODULE hCRYPTO;
+#endif /* NT */
+    debug(F111,"ck_ssh_is_installed","hCRYPTO",hCRYPTO);
+    return(ssl_installed && (hCRYPTO != NULL));
+#else /* SSLDLL */
+    return(ssl_installed);
+#endif /* SSLDLL */
+#else
+    return 0;
+#endif
+}
+
+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 <pwd.h>                    /* Password file for home directory */
+#endif /* UNIX */
+#ifdef OS2
+#include <process.h>
+#endif /* OS2 */
+#ifdef OS2ONLY
+#include "ckotcp.h"
+#endif /* OS2ONLY */
+
+#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_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_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));
+
+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);
+
+    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 (ssl_verbose_flag && !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",
+                       ctx->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;
+
+    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 (ssl_verbose_flag && 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;
+
+    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 */
+{
+    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 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;
+    extern int quiet;
+
+#ifndef NO_RSA
+    if (rsa_tmp == NULL)
+    {
+        if (ssl_debug_flag)
+            printf("Generating temporary (%d bit) RSA key...\r\n",keylength);
+
+        rsa_tmp=RSA_generate_key(keylength,RSA_F4,NULL,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;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    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))
+        return(NULL);
+    return(dh);
+}
+
+static DH *
+get_dh768()
+{
+    DH *dh=NULL;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    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))
+        return(NULL);
+    return(dh);
+}
+
+static DH *
+get_dh1024()
+{
+    DH *dh=NULL;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    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))
+        return(NULL);
+    return(dh);
+}
+
+static DH *
+get_dh1536()
+{
+    DH *dh=NULL;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    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))
+        return(NULL);
+    return(dh);
+}
+
+static DH *
+get_dh2048()
+{
+    DH *dh=NULL;
+
+    if ((dh=DH_new()) == NULL)
+        return(NULL);
+    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))
+        return(NULL);
+    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;
+    extern int quiet;
+
+#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)
+{
+    if ( !ck_ssleay_is_installed() )
+        return;
+
+    if (ssl == NULL)
+        return;
+
+    if (ssl->expand == NULL || ssl->expand->meth == NULL)
+        printf("Compression: None\r\n");
+    else {
+        printf("Compression: %s\r\n",ssl->expand->meth->name);
+    }
+}
+
+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;
+    SSL_CIPHER * cipher;
+    const char *cipher_list;
+    char buf[512]="";
+
+    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="<NULL>";
+    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="<NULL>";
+        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;
+    extern int quiet;
+
+    if ( !ck_ssleay_is_installed() )
+        return(0);
+
+    debug(F111,"tls_load_certs","SSL_CTX",ctx);
+    debug(F111,"tls_load_certs","SSL",con);
+    debug(F111,"tls_load_certs","server",server);
+
+    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 */
+{
+    COMP_METHOD * cm;
+
+    if ( !ck_ssleay_is_installed() )
+        return;
+
+    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) 
+#ifdef OS2
+         || 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.");
+        printf("  SSL\\TLS support 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 */
+
+#ifdef ZLIB
+    cm = COMP_zlib();
+    if (cm != NULL && cm->type != NID_undef) {
+        SSL_COMP_add_compression_method(0xe0, cm); /* EAY's ZLIB ID */
+    }
+#endif /* ZLIB */
+    cm = COMP_rle();
+    if (cm != NULL && cm->type != NID_undef)
+        SSL_COMP_add_compression_method(0xe1, cm); /* EAY's RLE ID */
+
+    /* 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);
+
+        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);
+        }
+
+        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 <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);
+                ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
+            }
+            if ( !ssl_ctx ) {
+                debug(F110,"ssl_tn_init","SSLv3_client_method failed",0);
+                last_ssl_mode = -1;
+                return(0);
+            }
+#ifndef COMMENT
+            tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method());
+#else /* COMMENT */
+            tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
+            /* This can fail because we do not have RSA available */
+            if ( !tls_ctx ) {
+                debug(F110,"ssl_tn_init","SSLv23_client_method failed",0);
+                tls_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
+            }
+#endif /* COMMENT */
+            if ( !tls_ctx ) {
+                debug(F110,"ssl_tn_init","TLSv1_client_method 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 */
+            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);
+                ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_server_method());
+            }
+            if ( !ssl_ctx ) {
+                debug(F110,"ssl_tn_init","SSLv3_server_method failed",0);
+                last_ssl_mode = -1;
+                return(0);
+            }
+#ifdef COMMENT
+            tls_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_server_method());
+#else /* COMMENT */
+            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());
+            }
+#endif /* COMMENT */
+            if ( !tls_ctx ) {
+                debug(F110,"ssl_tn_init","TLSv1_server_method failed",0);
+                last_ssl_mode = -1;
+                return(0);
+            }
+        } 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);
+
+#ifndef COMMENT
+        /* 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);
+#else /* COMMENT */
+        SSL_CTX_set_session_cache_mode(ssl_ctx,SSL_SESS_CACHE_OFF);
+        SSL_CTX_set_session_cache_mode(tls_ctx,SSL_SESS_CACHE_OFF);
+#endif /* COMMENT */
+    }
+
+    /* 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_generate_key(512,RSA_F4,NULL,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)
+            kssl_ctx_setstring(ssl_con->kssl_ctx, KSSL_SERVER, szHostName);
+        if (tls_con->kssl_ctx != NULL)
+            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 ) {
+#ifdef COMMENT
+        /* too many web servers still do not support TLSv1 */
+        tls_http_ctx=(SSL_CTX *)SSL_CTX_new(TLSv1_client_method());
+#else /* COMMENT */
+        tls_http_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_client_method());
+        /* This can fail because we do not have RSA available */
+        if ( !tls_http_ctx ) {
+            debug(F110,"ssl_http_init","SSLv23_client_method failed",0);
+            tls_http_ctx=(SSL_CTX *)SSL_CTX_new(SSLv3_client_method());
+        }
+#endif /* COMMENT */
+        if ( !tls_http_ctx ) {
+            debug(F110,"ssl_http_init","TLSv1_client_method failed",0);
+            return(0);
+        }
+#ifdef USE_CERT_CB
+        SSL_CTX_set_client_cert_cb(tls_http_ctx,ssl_client_cert_callback);
+#endif /* USE_CERT_CB */
+    }
+
+    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
+     * that 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_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 */
+
+#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 *
+ssl_get_dNSName(ssl) SSL * ssl;
+{
+    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;
+                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;
+            }
+        }
+        X509V3_EXT_cleanup();
+    }
+cleanup:
+    if (ialt)           sk_GENERAL_NAME_free(ialt);
+    if (server_cert)    X509_free(server_cert);
+    return dns;
+}
+
+char *
+ssl_get_commonName(ssl) SSL * ssl;
+{
+    static char name[256];
+    int err;
+    X509 *server_cert;
+
+    if (server_cert = SSL_get_peer_certificate(ssl)) {
+        err = X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert),
+                NID_commonName, name, sizeof(name));
+        X509_free(server_cert);
+    }
+    if (err > 0)
+        return name;
+    else
+        return NULL;
+}
+
+char *
+ssl_get_issuer_name(ssl) SSL * ssl;
+{
+    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 *
+ssl_get_subject_name(ssl) SSL * ssl;
+{
+    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 <rse@engelschall.com>.
+  Comments by Ralf.
+*/
+int
+ssl_verify_crl(int ok, X509_STORE_CTX *ctx)
+{
+    X509_OBJECT obj;
+    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;
+
+    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.
+     */
+    memset((char *)&obj, 0, sizeof(obj));
+    X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL);
+    rc = X509_STORE_get_by_subject(store_ctx, X509_LU_CRL, subject, &obj);
+    X509_STORE_CTX_cleanup(store_ctx);
+    crl = obj.data.crl;
+    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);
+            X509_OBJECT_free_contents(&obj);
+            X509_STORE_CTX_free(store_ctx);
+            return 0;
+        }
+
+        /*
+         * Check date of CRL to make sure it's not expired
+         */
+        i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
+        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);
+            X509_OBJECT_free_contents(&obj);
+            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);
+            X509_OBJECT_free_contents(&obj);
+            X509_STORE_CTX_free(store_ctx);
+            return 0;
+        }
+        X509_OBJECT_free_contents(&obj);
+    }
+
+    /*
+     * Try to retrieve a CRL corresponding to the _issuer_ of
+     * the current certificate in order to check for revocation.
+     */
+    memset((char *)&obj, 0, sizeof(obj));
+    X509_STORE_CTX_init(store_ctx, crl_store, NULL, NULL);
+    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;
+    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 (ASN1_INTEGER_cmp(revoked->serialNumber,
+                                 X509_get_serialNumber(xs)) == 0) {
+
+                serial = ASN1_INTEGER_get(revoked->serialNumber);
+                cp = X509_NAME_oneline(issuer, NULL, 0);
+                free(cp);
+
+                X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
+                X509_OBJECT_free_contents(&obj);
+                return 0;
+            }
+        }
+        X509_OBJECT_free_contents(&obj);
+    }
+    return ok;
+}
+
+char *
+tls_userid_from_client_cert(ssl) SSL * ssl;
+{
+    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;
+}
+
+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;
+                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++;
+                }
+            }
+        }
+        X509V3_EXT_cleanup();
+    }
+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 = 0, c2 = 0, 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;
+    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 (ssl_verbose_flag)
+        printf(prefix);
+    return(ok);
+}
+
+#ifndef HPUX10
+#ifndef HPUX1100
+#ifndef SCO_OSR505
+#ifndef OpenBSD
+#ifndef FREEBSD4
+#ifndef LINUX
+#ifndef AIX41
+#ifndef UW7
+#ifndef SOLARIS9
+#ifndef SOLARIS8
+#ifndef SOLARIS7
+#ifdef DEC_TCPIP
+#define inet_aton INET_ATON
+#endif /* DEC_TCPIP */
+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);
+    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 /* SOLARIS7 */
+#endif /* SOLARIS8 */
+#endif /* SOLARIS9 */
+#endif /* UW7 */
+#endif /* AIX41 */
+#endif /* LINUX */
+#endif /* FREEBSD4 */
+#endif /* OpenBSD */
+#endif /* SCO_OSR505 */
+#endif /* HPUX1100 */
+#endif /* HPUX10 */
+
+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;
+
+    if (ssl_verbose_flag && !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)
+{
+    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;
+}
+
+int
+tls_is_anon(int x)
+{
+    char buf[128];
+    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];
+    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;
+
+    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 ( ssl_verbose_flag )
+            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 ( ssl_verbose_flag ) {
+                    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 ( ssl_verbose_flag ) {
+                    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 ( ssl_verbose_flag ) {
+                    printf("[SSL - OK]\r\n");
+                }
+                debug(F110,"ssl_reply","[SSL - OK]",0);
+
+                ssl_active_flag = 1;
+                ssl_display_connect_details(ssl_con,0,ssl_verbose_flag);
+            }
+        }
+        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 ( ssl_verbose_flag ) {
+            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;
+
+    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 ( ssl_verbose_flag )
+                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 ( ssl_verbose_flag ) {
+                    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 ( ssl_verbose_flag )
+                    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 ( ssl_verbose_flag ) {
+                printf("[SSL - OK]\r\n");
+            }
+            debug(F110,"ssl_is","[SSL - OK]",0);
+            ssl_active_flag = 1;
+            ssl_display_connect_details(ssl_con,1,ssl_verbose_flag);
+
+            /* 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);
+
+    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 ( ssl_verbose_flag )
+                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 ( ssl_verbose_flag ) {
+                    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 ( ssl_verbose_flag )
+                    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 ( ssl_verbose_flag ) {
+                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,ssl_verbose_flag);
+
+
+#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 ( ssl_verbose_flag )
+                    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 ( ssl_verbose_flag )
+                    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 ( ssl_verbose_flag )
+            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 ( ssl_verbose_flag ) {
+                    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 ( ssl_verbose_flag ) {
+                    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 ( ssl_verbose_flag )
+                            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 ( ssl_verbose_flag )
+                                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 ( ssl_verbose_flag )
+                        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<len;i++ ) {
+                        sprintf(hexbuf,"%02X ",msg[i]);
+                        ckstrncat(tn_msg,hexbuf,TN_MSG_LEN);
+                    }
+                    printf("TLS client finished: %s\r\n",tn_msg);
+                }
+                tn_msg[0] = '\0';
+                len = ssl_get_server_finished(msg,len);
+                if ( len > 0 ) {
+                    for ( i=0;i<len;i++ ) {
+                        sprintf(hexbuf,"%02X ",msg[i]);
+                        ckstrncat(tn_msg,hexbuf,TN_MSG_LEN);
+                    }
+                    printf("TLS server finished: %s\r\n",tn_msg);
+                }
+            }
+
+            if (tn_deb || debses)
+                tn_debug("[TLS - OK]");
+            else if ( ssl_verbose_flag )
+                printf("[TLS - OK]\r\n");
+            debug(F110,"ck_tn_tls_negotiate","[TLS - OK]",0);
+
+            ssl_display_connect_details(tls_con,0,ssl_verbose_flag);
+        }
+        auth_finished(AUTH_REJECT);
+    }
+    accept_complete = 1;
+    auth_ssl_valid = 1;
+    return(0);
+}
+
+int
+ck_ssl_incoming(fd) int fd;
+{
+    /* if we are not running in debug then any error
+    * stuff from SSL debug *must* not go down
+    * the socket (which 0,1,2 are all pointing to by
+    * default)
+    */
+
+    int timo = 2000;
+
+    if ( !ck_ssleay_is_installed() )
+        return(-1);
+
+    /* do the SSL stuff now ... before we play with pty's */
+    SSL_set_fd(ssl_con,fd);
+    SSL_set_fd(tls_con,fd);
+
+    if (tls_only_flag) {
+        if (tn_deb || debses)
+            tn_debug("[TLS - handshake starting]");
+        else if ( ssl_verbose_flag )
+            printf("[TLS - handshake starting]\r\n");
+        debug(F110,"ck_ssl_incoming","[TLS - handshake starting]",0);
+
+        /* hmm ... only when running talking to things like
+        * https servers should we hit this code and then
+        * we really don't care *who* we talk to :-)
+        */
+        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 ( ssl_verbose_flag )
+                printf("[TLS - SSL_accept error]\r\n");
+
+            debug(F110,"ck_ssl_incoming",errbuf,0);
+            return(-1);
+        } else {
+            if (tn_deb || debses)
+                tn_debug("[TLS - OK]");
+            else if ( ssl_verbose_flag )
+                printf("[TLS - OK]\r\n");
+            debug(F110,"ck_ssl_incoming","[TLS - OK]",0);
+            tls_active_flag = 1;
+        }
+    } else if (ssl_only_flag) {
+        if (tn_deb || debses)
+            tn_debug("[SSL - handshake starting]");
+        else if ( ssl_verbose_flag )
+            printf("[SSL - handshake starting]\r\n");
+        debug(F110,"ck_ssl_incoming","[SSL - handshake starting]",0);
+
+        /* hmm ... only when running talking to things like
+         * https servers should we hit this code and then
+         * we really don't care *who* we talk to :-)
+         */
+        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 ( ssl_verbose_flag )
+                printf("[SSL - SSL_accept error]\r\n");
+
+            debug(F110,"ck_ssl_incoming",errbuf,0);
+            return(-1);
+        } else {
+            if (tn_deb || debses)
+                tn_debug("[SSL - OK]");
+            else if ( ssl_verbose_flag )
+            printf("[SSL - OK]\r\n");
+            debug(F110,"ssl_is","[SSL - OK]",0);
+            ssl_active_flag = 1;
+        }
+    }
+    if (ssl_active_flag || tls_active_flag) {
+        X509 *peer;
+        char str[256], *uid=NULL;
+
+        /* 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 on during the handshake (as it is an optional
+         * part of SSL and TLS)
+         */
+
+        if ( tls_active_flag ) {
+            peer=SSL_get_peer_certificate(tls_con);
+        } else if ( ssl_active_flag ) {
+            peer=SSL_get_peer_certificate(ssl_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("[SSL/TLS - peer check failed]");
+                else if (ssl_debug_flag) {
+                    printf("[SSL/TLS - peer check failed]\r\n");
+                }
+                debug(F110,
+                       "ck_tn_tls_negotiate",
+                       "[SSL/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
+                                       );
+            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
+                                       );
+            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);
+            }
+        }
+    }
+    return(0);  /* success */
+}
+
+int
+ck_ssl_outgoing(fd) int fd;
+{
+    int timo = 2000;
+
+    if ( !ck_ssleay_is_installed() )
+        return(-1);
+
+    /* bind in the network descriptor */
+    SSL_set_fd(ssl_con,fd);
+    SSL_set_fd(tls_con,fd);
+
+    /* If we are doing raw TLS then start it now ... */
+    if (tls_only_flag) {
+#ifndef USE_CERT_CB
+        if (!tls_load_certs(tls_ctx,tls_con,0)) {
+            debug(F110,"ck_ssl_outgoing","tls_load_certs() failed",0);
+            return(-1);
+        }
+#endif /* USE_CERT_CB */
+        if (tn_deb || debses)
+            tn_debug("[TLS - handshake starting]");
+        else if (ssl_verbose_flag)
+            printf("[TLS - handshake starting]\r\n");
+        debug(F110,"ck_ssl_outgoing","[TLS - handshake starting]",0);
+        if (SSL_connect(tls_con) <= 0) {
+            char errbuf[1024];
+
+            sprintf(errbuf,"[TLS - SSL_connect 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);
+
+            if (tn_deb || debses)
+                tn_debug("[TLS - FAILED]");
+            else if ( ssl_verbose_flag )
+                printf("[TLS - FAILED]\r\n");
+            debug(F110,"ck_ssl_outgoing","[TLS - FAILED]",0);
+            netclos();
+            return(-1);
+        } else {
+            tls_active_flag = 1;
+            if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) && 
+                 !tls_is_krb5(0) ) {
+                char *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 ( ssl_verbose_flag )
+                            printf("[TLS - FAILED]\r\n");
+                        debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+
+                        auth_finished(AUTH_REJECT);
+                        return -1;
+                    } else {
+                        char prmpt[1024];
+                        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 ( ssl_verbose_flag )
+                                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 ( ssl_verbose_flag )
+                        printf("[TLS - FAILED]\r\n");
+                    debug(F110,
+                           "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                    auth_finished(AUTH_REJECT);
+                    return -1;
+                }
+            }
+
+            printf("[TLS - OK]\r\n");
+            if (tn_deb || debses)
+                tn_debug("[TLS - OK]");
+            debug(F110,"ck_ssl_outgoing","[TLS - OK]",0);
+            ssl_display_connect_details(tls_con,0,ssl_verbose_flag);
+        }
+    }
+    /* if we are doing raw SSL then start it now ... */
+    else if (ssl_only_flag) {
+#ifndef USE_CERT_CB
+        if (!tls_load_certs(ssl_ctx,ssl_con,0))
+            return(-1);
+#endif /* USE_CERT_CB */
+        if (tn_deb || debses)
+            tn_debug("[SSL - handshake starting]");
+        else if ( ssl_verbose_flag )
+            printf("[SSL - handshake starting]\r\n");
+        debug(F110,"ck_ssl_outgoing","[SSL - handshake starting]",0);
+        if (SSL_connect(ssl_con) <= 0) {
+            if ( ssl_debug_flag ) {
+                char errbuf[1024];
+
+                sprintf(errbuf,"[SSL - SSL_connect error: %s",
+                         ERR_error_string(ERR_get_error(),NULL));
+                printf("%s\r\n",errbuf);
+            }
+            if (tn_deb || debses)
+                tn_debug("[SSL - FAILED]");
+            else if ( ssl_verbose_flag )
+                printf("[SSL - FAILED]\r\n");
+            debug(F110,"ck_ssl_outgoing","[SSL - FAILED]",0);
+            return(-1);
+        } else {
+            ssl_active_flag = 1;
+
+            if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) &&
+                 !tls_is_krb5(0)) {
+                char *subject = ssl_get_subject_name(ssl_con);
+
+                if (!subject) {
+                    if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+                    {
+                        if (tn_deb || debses)
+                            tn_debug("[SSL - FAILED]");
+                        else if ( ssl_verbose_flag )
+                            printf("[SSL - FAILED]\r\n");
+                        debug(F110,"ck_tn_tls_negotiate","[SSL - FAILED]",0);
+
+                        auth_finished(AUTH_REJECT);
+                        return -1;
+                    } else {
+                        char prmpt[1024];
+                        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("[SSL - FAILED]");
+                            else if ( ssl_verbose_flag )
+                                printf("[SSL - FAILED]\r\n");
+                            debug(F110,
+                                   "ck_tn_tls_negotiate","[SSL - FAILED]",0);
+                            auth_finished(AUTH_REJECT);
+                            return -1;
+                        }
+                    }
+                } else if (ssl_check_server_name(ssl_con, szHostName)) {
+                    if (tn_deb || debses)
+                        tn_debug("[SSL - FAILED]");
+                    else if ( ssl_verbose_flag )
+                        printf("[SSL - FAILED]\r\n");
+                    debug(F110, "ck_tn_tls_negotiate","[SSL - FAILED]",0);
+                    auth_finished(AUTH_REJECT);
+                    return -1;
+                }
+            }
+
+            printf("[SSL - OK]\r\n");
+            if (tn_deb || debses)
+                tn_debug("[SSL - OK]");
+            debug(F110,"ck_ssl_outgoing","[SSL - OK]",0);
+            ssl_display_connect_details(ssl_con,0,ssl_verbose_flag);
+        }
+    }
+    return(0);  /* success */
+}
+
+#ifndef NOHTTP
+int
+ck_ssl_http_client(fd, hostname) int fd; char * hostname;
+{
+    int timo = 2000;
+
+    if ( !ck_ssleay_is_installed() )
+        return(-1);
+
+    /* bind in the network descriptor */
+    SSL_set_fd(tls_http_con,fd);
+
+    /* If we are doing raw TLS then start it now ... */
+    if (1) {
+#ifndef USE_CERT_CB
+        if (!tls_load_certs(tls_http_ctx,tls_http_con,0)) {
+            debug(F110,"ck_ssl_http_client","tls_load_certs() failed",0);
+            return(-1);
+        }
+#endif /* USE_CERT_CB */
+        if (tn_deb || debses)
+            tn_debug("[TLS - handshake starting]");
+        else if (ssl_verbose_flag)
+            printf("[TLS - handshake starting]\r\n");
+        debug(F110,"ck_ssl_outgoing","[TLS - handshake starting]",0);
+        if (SSL_connect(tls_http_con) <= 0) {
+            char errbuf[1024];
+
+            sprintf(errbuf,"[TLS - SSL_connect 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);
+
+            if (tn_deb || debses)
+                tn_debug("[TLS - FAILED]");
+            else if ( ssl_verbose_flag )
+                printf("[TLS - FAILED]\r\n");
+            debug(F110,"ck_ssl_http_client","[TLS - FAILED]",0);
+            http_close();
+            return(-1);
+        } else {
+            tls_http_active_flag = 1;
+            if ( !ssl_certsok_flag && (ssl_verify_flag & SSL_VERIFY_PEER) &&
+                 !tls_is_krb5(3) ) {
+                char *subject = ssl_get_subject_name(tls_http_con);
+
+                if (!subject) {
+                    if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+                    {
+                        if (tn_deb || debses)
+                            tn_debug("[TLS - FAILED]");
+                        else if ( ssl_verbose_flag )
+                            printf("[TLS - FAILED]\r\n");
+                        debug(F110,"ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                        return -1;
+                    } else {
+                        char prmpt[1024];
+                        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 ( ssl_verbose_flag )
+                                printf("[TLS - FAILED]\r\n");
+                            debug(F110,
+                                   "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                            return -1;
+                        }
+                    }
+                } else if (ssl_check_server_name(tls_http_con, hostname)) {
+                    if (tn_deb || debses)
+                        tn_debug("[TLS - FAILED]");
+                    else if ( ssl_verbose_flag )
+                        printf("[TLS - FAILED]\r\n");
+                    debug(F110,
+                           "ck_tn_tls_negotiate","[TLS - FAILED]",0);
+                    return -1;
+                }
+            }
+
+            printf("[TLS - OK]\r\n");
+            if (tn_deb || debses)
+                tn_debug("[TLS - OK]");
+            debug(F110,"ck_ssl_outgoing","[TLS - OK]",0);
+            ssl_display_connect_details(tls_http_con,0,ssl_verbose_flag);
+        }
+    }
+    return(0);  /* success */
+}
+#endif /* NOHTTP */
+int
+ck_ssl_renegotiate_ciphers()
+{
+
+    if ( !ck_ssleay_is_installed() )
+        return(0);
+
+    if ( !sstelnet )
+        return(0);
+
+    if ( ssl_active_flag )
+        return SSL_renegotiate(ssl_con);
+    else if ( tls_active_flag )
+        return SSL_renegotiate(tls_con);
+    return(0);
+}
+
+#ifdef NT
+int 
+ck_X509_save_cert_to_user_store(X509 *cert)
+{
+#ifdef X509V3_EXT_DUMP_UNKNOWN
+    char path[CKMAXPATH];
+    char hash[16];
+    char * GetAppData(int);
+    BIO * out=NULL;
+
+    if ( cert == NULL )
+        return(0);
+
+    sprintf(hash,"%08lx",X509_subject_name_hash(cert));
+    ckmakmsg(path,CKMAXPATH,GetAppData(0),"kermit 95/certs/",
+             hash,".0");
+
+    
+    out=BIO_new(BIO_s_file());
+    if (out == NULL)
+    {
+        ERR_print_errors(bio_err);
+        return(0);
+    }
+    if (BIO_write_filename(out,path) <= 0) {
+        perror(path);
+        return(0);
+    }
+
+    X509_print_ex(out, cert, XN_FLAG_SEP_MULTILINE, X509V3_EXT_DUMP_UNKNOWN);
+    if (!PEM_write_bio_X509(out,cert)) {
+        BIO_printf(bio_err,"unable to write certificate\n");
+        ERR_print_errors(bio_err);
+        BIO_free_all(out);
+        return(0);
+    }
+    BIO_free_all(out);
+    return(1);
+#else /* X509V3_EXT_DUMP_UNKNOWN */
+    return(0);
+#endif /* X509V3_EXT_DUMP_UNKNOWN */
+}
+#endif /* NT */
+
+#ifndef OS2
+/* The following function should be replaced by institution specific */
+/* code that will convert an X509 cert structure to a userid for the */
+/* purposes of client to host login.  The example code included      */
+/* simply returns the UID field of the Subject if it exists.         */
+
+/* X509_to_user() returns 0 if valid userid in 'userid', else -1 */
+int
+X509_to_user(X509 *peer_cert, char *userid, int len)
+{
+#ifdef X509_UID_TO_USER
+    /* BEGIN EXAMPLE */
+    int err;
+
+    if (!(peer_cert && userid) || len <= 0)
+        return -1;
+
+    userid[0] = '\0';
+    debug(F110,"X509_to_user() subject",
+           X509_NAME_oneline(X509_get_subject_name(peer_cert),NULL,0),0);
+
+    /* userid is in cert subject /UID */
+    err = X509_NAME_get_text_by_NID(X509_get_subject_name(peer_cert),
+#ifndef NID_x500UniqueIdentifier
+                                     NID_uniqueIdentifier,
+#else
+                                     NID_x500UniqueIdentifier,
+#endif
+                                     userid, len);
+
+    debug(F111,"X509_to_user() userid",userid,err);
+    if (err > 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 ( 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:
+    X509V3_EXT_cleanup();
+    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 (!ASN1_STRING_cmp(peer_cert->signature, file_cert->signature))
+            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 */
diff --git a/ckermit-8.0.211/ck_ssl.h b/ckermit-8.0.211/ck_ssl.h
new file mode 100644
index 0000000..b4dd8a3
--- /dev/null
+++ b/ckermit-8.0.211/ck_ssl.h
@@ -0,0 +1,147 @@
+/*
+  C K _ S S L . H --  OpenSSL Interface Header for C-Kermit
+
+  Copyright (C) 1985, 2004,
+    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
+*/
+
+#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
+#include <openssl/comp.h>
+#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
+#include <openssl/des.h>
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/bn.h>
+#include <openssl/blowfish.h>
+#include <openssl/dh.h>
+#include <openssl/rc4.h>
+#include <openssl/cast.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#ifdef SSL_KRB5
+#include <openssl/kssl.h>
+#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;
+
+#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 *));
+#ifdef OS2
+#include "ckosslc.h"
+#include "ckossl.h"
+#endif /* OS2 */
+
+#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 */
diff --git a/ckermit-8.0.211/ckaaaa.txt b/ckermit-8.0.211/ckaaaa.txt
new file mode 100644
index 0000000..efa83a5
--- /dev/null
+++ b/ckermit-8.0.211/ckaaaa.txt
@@ -0,0 +1,385 @@
+ckaaaa.txt                                                        10 Apr 2004
+
+			   C-KERMIT VERSION 8.0.211
+			      OVERVIEW OF FILES
+
+	       Communications software for UNIX and (Open)VMS.
+
+		       And in former versions also for:
+			  Stratus VOS, AOS/VS, QNX,
+	     Plan 9, OS-9, Apollo Aegis, and the Commodore Amiga.
+		      The Apple Macintosh, the Atari ST.
+
+		  The Kermit Project - Columbia University
+
+	    http://www.columbia.edu/kermit/ - kermit@columbia.edu
+
+
+  Copyright (C) 1985, 2004,
+    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.
+
+
+DOCUMENTATION
+
+  C-Kermit is documented in the book "Using C-Kermit", Second Edition, by
+  Frank da Cruz and Christine M. Gianone, Digital Press, ISBN 1-55558-164-1,
+  supplementated by Web-based updates for C-Kermit 7.0 and 8.0.
+
+PLATFORMS
+                   Security
+   Name            Included   Last Updated
+
+   Unix               Yes     8.0.211  10 Apr 2004
+   (Open)VMS          No      8.0.208  10 Apr 2004
+   Windows (K95)      Yes     8.0.208  14 Mar 2003  (K95 2.1)
+   OS/2 (K95)         Yes     8.0.208  14 Mar 2003  (K95 2.1)
+   DG AOS/VS          No      7.0.196   1 Jan 2000
+   Stratus VOS        No      7.0.196   1 Jan 2000
+   Bell Plan 9        No      7.0.196   1 Jan 2000
+   Microware OS-9     No      7.0.196   1 Jan 2000
+   Commodore Amiga    No      7.0.196   1 Jan 2000
+   Macintosh          No      5A(190)  16 Aug 1994  (Mac Kermit 0.991)
+   Atari ST           No      5A(189)  30 Jun 1993
+
+QUICK START FOR FTP USERS
+
+  If you have a Web browser, go to:
+
+    http://www.columbia.edu/kermit/ckermit.html
+
+  And take it from there.  Otherwise...
+
+  The definitive FTP source for Kermit software is kermit.columbia.edu.
+  Kermit software obtained from other FTP sites is not necessarily complete
+  or up to date, and may have been modified.
+
+C-Kermit for UNIX computers that have a C compiler and 'make' program:
+
+  Directory kermit/archives, binary mode, file cku211.tar.Z or cku211.tar.gz
+
+  This is a compressed tar archive of UNIX C-Kermit source code, makefile, and
+  other files.  It unpacks into its current directory, so download it into a
+  fresh directory.  Transfer in binary mode, uncompress (or gunzip), untar (tar
+  xvf cku211.tar), and then give the appropriate "make" command to build for
+  your UNIX system; read the comments in the makefile and ckuins.txt for
+  further info.
+
+C-Kermit for VMS:
+
+  If you have VMS UNZIP, get the file kermit/archives/ckv211.zip in binary
+  mode, unzip, and build with CKVKER.COM.
+
+Others:  In the kermit/f or kermit/test directories under the appropriate
+prefixes, explained below.
+
+
+INSTALLATION
+
+Installation procedures depend on the system.  Please read the CK?INS.TXT,
+if any, file for your system (?=U for UNIX, V for VMS, etc).  Please note
+the naming and placement for the initialization files:
+
+  CKERMIT.INI
+    The standard initialization file.  Please leave it as is unless you
+    know what you are doing and (if you are changing it or replacing it
+    for others to use) you are prepared to support it.  Rename this file
+    to .kermrc in UNIX, OS-9, BeBox, or Plan 9.  In Stratus VOS, rename
+    it ckermit.ini (lowercase).  On multiuser systems, it goes either in the
+    (or EACH) user's home (login) directory, or else in a common shared
+    place if C-Kermit has been configured to look in that place (see
+    ckccfg.txt for details).
+
+  CKERMOD.INI
+    A *sample* customization file.  On multiuser OS's, a copy of this file
+    goes in each user's home directory, and then each user edits it to suit
+    her needs and preferences; e.g. by defining macros for their common
+    connections.
+
+  DIALING DIRECTORIES
+    Dialing directory files can be system-wide, per-group, or per-user, or
+    any combination.  For example, there can be a corporate wide directory
+    shared by all users, a supplemental directory for each division or
+    department, and a personal directory for each user.  Simply be sure the
+    dialing directory files are identified a SET DIAL DIRECTORY command in
+    the user's (or the system-wide) C-Kermit initialization file, or in the
+    environment variable (logical name, symbol) K_DIAL_DIRECTORY.  (The
+    standard initialization file looks by default in the user's home or login
+    directory.)  When installing C-Kermit on multiuser platforms from which
+    users will dial out, you can also set environment variables for area
+    code, country code, and the various dialing prefixes as described on page
+    478 of "Using C-Kermit" (second edition), so users don't have to worry
+    about defining these items themselves.   Network directories and service
+    directories can also be set up in a similar manner.
+
+  DOCUMENTATION
+    In UNIX, the general C-Kermit man page (or one of the versions tailored
+    for a specific platform, like HP-UX or Solaris) should be installed in
+    the appropriate place.  In VMS, the VMS help topic (CKVKER.HLP) should
+    be installed as described in CKVINS.TXT.  Plain-text documentation such
+    as CKERMIT2.TXT should be put in whatever place people are accustomed
+    to looking.
+
+FILES AND FILE NAMING CONVENTIONS
+
+C-Kermit is a family of Kermit programs for many different computer systems.
+The program shares a common set of system-independent file transfer protocol
+modules, written in the C language.  System-dependent operations are collected
+into system-specific modules for each system.
+
+C-Kermit file names all start with the letters "CK", followed by a single
+letter indicating the subgroup.  When referring to these files in the UNIX,
+AOS/VS, or VOS environments, use lowercase letters, rather than the uppercase
+letters shown here.  Subgroups:
+
+  _: Security/Authentication/Encryption code, possibly regulated by law
+  a: General descriptive material and documentation
+  b: BOO file encoders and decoders (obsolete)
+  c: All platforms with C compilers
+  d: Data General AOS/VS
+  e: Reserved for "ckermit" files, like CKERMIT.INI, CKERMIT80.TXT
+  f: (reserved)
+  g: (reserved)
+  h: (reserved)
+  i: Commodore Amiga (Intuition)
+  j: (unused)
+  k: (unused)
+  l: Stratus VOS
+  m: Macintosh with Mac OS
+  n: Microsoft Windows NT
+  o: OS/2 and/or Microsoft Windows 95/98/ME/NT/2000/XP/...
+  p: Bell Labs Plan 9
+  q: (reserved)
+  r: DEC PDP-11 with RSTS/E (reserved)
+  s: Atari ST GEMDOS (last supported in version 5A(189))
+  t: DEC PDP-11 with RT-11 (reserved)
+  u: UNIX or environments with UNIX-like C libraries
+  v: VMS and OpenVMS
+  w: Wart (Lex-like preprocessor, used with all systems)
+  x: (reserved)
+  y: (reserved)
+  z: (reserved)
+  0-3: (reserved)
+  4: IBM AS/400 (reserved)
+  5-8: (reserved)
+  9: Microware OS-9
+
+Examples:
+
+  ckaaaa.txt - This file
+  ckufio.c   - File i/o for UNIX
+  ckstio.c   - Communications i/o for the Atari ST
+  makefile   - makefile for building UNIX C-Kermit
+  ckpker.mk  - makefile for building Plan 9 C-Kermit
+  ckvker.com - build procedure for VMS C-Kermit
+
+IMPORTANT FILES (use lowercase names on UNIX, VOS, or AOS/VS):
+
+  ckaaaa.txt  - This file (overview of the C-Kermit files).
+                For system-specific distributions, this will normally
+                be replaced by a system-specific READ.ME file.
+
+  ckermit70.txt - Updates: Supplement to "Using C-Kermit", 2nd Ed, for 7.0.
+  ckermit80.txt - Updates: Supplement to "Using C-Kermit", 2nd Ed, for 8.0.
+  ckututor.txt  - C-Kermit Tutorial for Unix (plain text)
+  ckcbwr.txt  - "Beware file" (limitations, known bugs, hints), general.
+  ckermit.ini - Standard initialization file (rename to .kermrc in UNIX, OS-9)
+  ckermod.ini - Sample customization file (rename to .mykermrc in UNIX, OS-9)
+
+The following can be found at the Kermit FTP site:
+
+  ckermit.kdd - Sample dialing directory file (rename to .kdd in UNIX, OS-9)
+  ckermit.knd - Sample dialing directory file (rename to .knd in UNIX, OS-9)
+  ckermit.ksd - Sample services directory file (rename to .ksd in UNIX, OS-9)
+  ckedemo.ksc - Demonstration macros from "Using C-Kermit"
+  ckepage.ksc - Ditto
+  ckevt.ksc   - Ditto
+
+UNIX-specific files:
+
+  ckuins.txt - UNIX-specific installation instructions.
+  ckubwr.txt - UNIX-specific beware file.
+  ckuker.nr  - "man page" for UNIX.
+
+VMS-specific files:
+
+  ckvins.txt - VMS-specific installation instructions.
+  ckvbwr.txt - VMS-specific beware file
+  ckvker.hlp - VMS C-Kermit HELP topic (needs updating).
+
+DG AOS/VS-specific files:
+
+  ckdins.txt - Data General AOS/VS C-Kermit installation instructions
+  ckdbwr.txt - AOS/VS "beware" file
+  ckd*.cli   - Procedures for building AOS/VS C-Kermit
+
+The following files are of interest mainly to programmers and historians
+(find them at the Kermit ftp site):
+
+  ckcker.ann - Release announcements.
+  ckccfg.txt - Configuration information (feature selection), general.
+  ckcplm.txt - Program logic manual (for programmers).
+  ckc211.txt - Program update history for edit 201-211.
+  ckc200.txt - Program update history for edit 198-200 (big)
+  ckc197.txt - Program update history for edit 195-197 (big)
+  ckc190.txt - Program update history for edits 189-190 (big).
+  ckc188.txt - Program update history, edits 179-188 (big).
+  ckc178.txt - Program edit history, 5A edits through 178 (very big).
+  ckcv4f.txt - Program edit history, version 4F.
+  ckcv4e.txt - Program edit history, version 4E.
+
+BINARIES
+
+If you have FTP access to kermit.columbia.edu (also known as
+kermit.cc.columbia.edu, ftp.cc.columbia.edu), you can also retrieve various
+C-Kermit binaries from the directory kermit/bin/ck*.*, or more conventiently
+from the web page:
+
+  http://www.columbia.edu/kermit/ck80binaries.html
+
+Test versions would be in kermit/test/bin/ck*.*.  Be sure to transfer these
+files in binary mode.  The READ.ME file in that directory explains what's
+what.
+
+SOURCE FILES
+
+The source files for the UNIX version (all UNIX versions) are available in
+kermit/archives/ckuNNN.tar.Z, approximately 1MB in size.  Transfer this file
+in binary mode.  This is a compressed tar archive.  There is also a gzip'd
+version, cku211.tar.gz.  To get the binary tar archive:
+
+  mkdir kermit                   (at shell prompt, make a Kermit directory)
+  cd kermit                      (make it your current directory)
+
+  ftp kermit.columbia.edu        (make an ftp connection)
+  user: anonymous                (log in as user "anonymous", lower case!)
+  password:                      (use your email id as a password)
+  cd kermit/archives             (go to the archives directory)
+  type binary                    (specify binary file transfer)
+  get cku211.tar.Z               (get the tar archive) (or get cku192.tar.gz)
+  bye                            (disconnect and exit from ftp)
+
+  uncompress cku211.tar.Z        (at the shell prompt, uncompress the archive)
+  tar xvf cku211.tar             (extract the files from the tar archive)
+  make xxx                       (build C-Kermit for your system)
+
+(where "xxx" is the makefile entry appropriate for your system.)
+
+All C-Kermit source and other text files are also kept separately in the
+kermit/f directory.  The files necessary to build a particular implementation
+of C-Kermit are listed in the appropriate makefile or equivalent:
+
+       UNIX: makefile (or rename ckuker.mak to makefile)
+   2.11 BSD: ckubs2.mak (rename to makefile), ckustr.sed
+     Plan 9: ckpker.mk  (rename to mkfile)
+  Macintosh: ckmker.mak (rename to kermit.make, use MPW C 3.2)
+        VMS: CKVKER.COM (DCL) (and optionally also CKVKER.MMS)
+             or CKVOLD.COM (for VMS 4.x)
+      Amiga: CKIKER.MAK (Aztec C) or CKISAS.MAK (SAS C)
+   Atari ST: CKSKER.MAK
+       OS-9: ck9ker.mak or ck9ker.gcc
+     AOS/VS: ckdmak.cli, ckdcc.cli, ckdlnk.cli
+Stratus VOS: cklmak.cm
+
+Minimal source files for building selected versions (these patterns get all
+the files you need, and in some cases maybe a few extra):
+
+   UNIX:   ck[cuw]*.[cwh]  (including QNX, Plan 9, and BeBox)
+   UNIX:   ck[cuw_]*.[cwh] (Unix with security modules)
+   VMS:    ck[cuwv]*.[cwh]
+   Mac:    ck[cuwm]*.[cwhr]
+   AOS/VS: ck[cuwd]*.[cwh]
+   VOS:    ck[cwhl]*.[cwh]
+   Amiga:  ck[cuwi]*.[cwh]
+   Atari:  ck[cuws]*.[cwh]
+   OS-9:   ck[cuw9]*.[cwha]
+
+For a detailed, specific source file list for this C-Kermit release, see the
+file ckcxxx.txt, where xxx is the current C-Kermit edit number, such as 211.
+
+Finally, here is a more detailed description of the C-Kermit file naming
+conventions.  A C-Kermit filename has the form:
+
+  CK<system><what>.<type>
+
+where:
+
+<system> is described earlier in this file;
+
+<type> is the file type (use lowercase on UNIX, VOS, or AOS/VS):
+
+  c:   C language source
+  h:   Header file for C language source
+  w:   Wart preprocessor source, converted by Wart (or Lex) to a C program
+  r:   Macintosh resource file (8-bit text)
+  a:   Assembler source
+
+  txt: Plain text.
+  nr:  Nroff/Troff text formatter source for UNIX "man page"
+  mss: Scribe text formatter source
+  ps:  Typeset material to be printed on a PostScript printer
+  hlp: A VMS Help topic
+
+  ini: Initialization file
+  ksc: A Kermit Script to be executed by the TAKE command
+  kdd: A Kermit Dialing Directory
+  knd: A Kermit Network Directory
+  ksd: A Kermit Services Directory
+
+  mak: A Makefile or other build procedure (often needs renaming)
+  com: (VMS only) a DCL command procedure
+  cli: (AOS/VS only) a command procedure
+  cmd: (OS/2 only) a Rexx command procedure
+
+  boo: "boo"-encoded executable program, decode with CKBUNB program.
+  hex: "hex"-encoded executable program, decode with CKVDEH program (VMS only).
+  hqx: BinHex'd Macintosh Kermit program, decode with BinHex version 4.0.
+  uue: A uuencoded binary file, decode with uudecode or (DG only) CKDECO.
+
+  def: An OS/2 linker definitions file.
+  sh:  A UNIX shell script.
+  sed: A UNIX sed (editor) script.
+  str: A file of character strings extracted from C-Kermit (BSD 2.1x only).
+
+<what> is mnemonic (up to 3 characters) for what's in the file:
+
+NOTE: After C-Kermit 6.0, text filetypes such as .DOC and .HLP were changed
+to .TXT to avoid confusion in Windows-based Web browsers, which would
+otherwise mistake them for Microsoft Word or Windows Help documents.
+
+  aaa: A "read-me" file, like this one
+  ins: Installation instructions or procedures
+  bwr: "Beware" file -- things to watch out for, hints and tips
+  plm: Program Logic Manual
+  ker: General C-Kermit definitions, information, documentation
+
+  nnn: Digits: C-Kermit edit number (e.g. cku211.tar.gz)
+  cmd: Command parsing
+  con: CONNECT command
+  cns: CONNECT command (UNIX only - version that uses select(), not fork())
+  deb: Debug/Transaction Log formats, Typedefs
+  dia: Modem/Dialer control
+  fio: System-depdendent File I/O
+  fns: Protocol support functions
+  fn2: More protocol support functions (and FN3, ...)
+  lib: Common library routines module
+  mai: Main program
+  net: Network i/o module
+  pro: Protocol
+  scr: SCRIPT command
+  tel: Telnet protocol module
+  tio: System-dependent communications i/o & control and interrupt handing
+  sig: Signal handling module
+  usr: Interactive/script user interface
+  us2: More user interface (mainly help text)
+  us3: Still more user interface (and USR4, USR5, USR6, USR7)
+  usx: Common user interface functions
+  usy: Command-line parsing
+  xla: Character set translation module
+  uni: Unicode support
+  pty: Pseudoterminal support
+  mdb: Malloc-debugging module (not included in real builds)
+  str: Strings module (only for 2.xBSD)
+
+(End of ckaaaa.txt)
diff --git a/ckermit-8.0.211/ckc211.txt b/ckermit-8.0.211/ckc211.txt
new file mode 100644
index 0000000..1886725
--- /dev/null
+++ b/ckermit-8.0.211/ckc211.txt
@@ -0,0 +1,3595 @@
+C-KERMIT CHANGE LOG (Changes since 8.0.200 of 12 Dec 2001)
+
+Chronological order: Go to the bottom to find the newest edits.
+
+---8.0.200---
+
+Known bugs (+ = fixed after release):
+
+ + 1. tilde_expand() can call getcwd() with NULL arg.
+ + 2. getexedir() called too early (fatal in combination with (1)).
+ + 3. Kermit "get blah" where blah is a symlink; server refuses to send it.
+      Should not do this if GET not recursive.
+ ? 4. Dave Sneddon's report about VMS fore/background confusion.
+ + 5. FTP GET path/file doesn't work - path not stripped - but MGET works.
+ + 6. IRIX 5.3 compilation problems (have patches from Marcus Herbert)
+ X 7. Filename completion bug (see below) (deferred).
+ + 8. QNX6 herald and other problems.
+
+-------------
+
+Merged Jeff's changes, 20 Dec 2001:
+
+ . Changed all occurrences of "ttnproto == NP_TELNET" to "IS_TELNET()" to
+   account for the difference between SSH and Telnet.  ckuscr.c,
+   ckuus[3457].c, ckcnet.h, ckcfns.c, ckudia.c, ckutio.c, ckucon.c, ckucns.c.
+
+ . Moved SSH pty failure warnings.  ckuusr.c.
+
+ . Security adjustments to FTP module, plus fix an error message.  ckcftp.c.
+
+ . Adjustment of some security-related #ifdefs. ckcdeb.h, ckuus2.c, ckctel.c.
+
+ . Guard against calling getpwnam() with a NULL arg in tilde_expand() ckufio.c.
+ 
+ . Moved getexedir() call to later, where it's safe.  ckcmai.c.
+
+Added SSH ADD and many SSH SET commands from Jeff's spec.  Fixed SHOW SSH
+to not dump core if variables weren't set.  ckcker.h, ckuus[r3].c, 20 Dec 2001.
+
+C-Kermit in server mode, client says "get foo" where foo is a symlink.
+Server says "no files meet selection criteria" instead of sending the file.
+It should only refuse to follow symlinks if it's a recursive get.  Fixed
+in sgetinit(): ckcpro.w, 21 Dec 2001.
+
+More work on SSH and SET/SHOW SSH commands.  ckuus[r3].c, 21 Dec 2001.
+
+Undid Jeff's replacement of the SSH pseudoterminal allocation failure
+message, because now it comes out any time an SSH command has to be
+reparsed (in the non-SSHBUILTIN case).  ckuusr.c, 21 Dec 2001.
+
+More SSH and SET SSH command work back & forth with Jeff, plus Jeff added
+SET HOST /NET:SSH.  ckcmai.c, ckuus[r37].c, ckcdeb.h, ckuusr.h, 22 Dec 2001.
+
+Added SSH OPEN switches.  ckuusr.c, 22 Dec 2001.
+
+Added SSH CLEAR, HELP SSH, and HELP SET SSH.  ckuus[r2].c, 23 Dec 2001.
+
+From Jeff:
+ . SET TCP commands now apply to SSH
+ . SSH V2 REKEY and FORWRD-{LOCAL,REMOTE}-PORT  commands now implemented
+ . Missing DLLs automatically disable appropriate authentication mechanisms.
+ckuusr.c ckcnet.c ckuus3.c ckcmai.c ckcnet.h ckuus4.c, 26 Dec 2001.
+
+From Jeff:
+ . Remove SET SSH KEEPALIVES.
+ . Add help text for SSH AGENT { ADD, DELETE, LIST }.
+ckuus[23].c, 28 Dec 2001.
+
+Added parsing for SSH AGENT { ADD, DELETE, LIST }.  ckuusr.c, 28 Dec 2001.
+
+From Jeff:
+ . Fixed a crash that can happen when making an SSH connection.
+ . Filled in SSH AGENT actions.
+ . Changed default for strict host key check (to ASK) and help text.
+ . uploaded new binaries include ~kermit/os2test/beta/ssh-agent.exe
+ . Read man ssh-agent on ftp.kermit.columbia.edu for details on what it does.
+ckuus[r23].c, 28 Dec 2001.
+
+"ftp get path/filename" didn't work; the FTP client did not strip the path
+from the local copy of the filename when doing a GET, even though it did
+for MGET.  Diagnosis: in doftpget(), the "if (!getone && !skipthis)" statement
+lacked an "else" part for the getone case.  ckcftp.c, 28 Dec 2001.
+
+A while back Jeff reported that in FTP MGET, if you cancel a file with 'x',
+all the rest of the files arrive truncated to 0 bytes.  I tried this on both
+Unix and Windows and couldn't reproduce it.
+
+In the last-minute flurry to release C-Kermit 8.0, I thought I noticed the FTP
+client failing to update the fullscreen file-transfer display.  But it seems
+to work right, at least in Unix.  When downloading a big file with FTP, all
+the display fields are updated as expected.  But smaller files might go by too
+fast for the display to do anything.  HOWEVER, in K95 the file transfer
+display does not update itself until the end of the file, even if the file
+takes a long time to transfer.  This happens in both the Console and GUI
+versions.  A thread thing?  (Jeff says no.)  Yet the same display works fine
+on Telnet connections.
+
+In IRIX 5.3, the select()-based CONNECT module had to include <sys/time.h>
+or else it blew up with "struct timeval" unknown.  Since there already was
+a SYSTIMEH CFLAG, I added the #include within #ifdef SYSTIMEH..#endif and
+rebuilt with KFLAGS=-DSYSTIMEH, only to discover that the irix5* targets
+didn't bother to propogate KFLAGS.  Fixed in ckucns.c, makefile, 30 Dec 2001.
+
+Increased IRIX5x Olimit from 2400 to 3000 because of ckuus[34].c.  Added
+-ansi, since (Marcus Herbert reported) we were not actually getting ANSI-C
+compilation even though CK_ANSIC was defined.  But now that we are, we get
+warnings in <netinet/tcp.h>, which is included by ckcnet.h:
+
+  bit-field 'th_off' type required to be int, unsigned int, or signed int.
+  (3.5.2.1(30))
+	  u_char  th_off:4,
+	  ------  ^
+Tough.  makefile, 30 Dec 2001.
+
+But adding -ansi to the IRIX 5x targets also make compilation bomb whenever we
+referenced fdopen() or popen(), which evidently don't have prototypes in any
+of the header files.  Luckily we already have CFLAGS for this occasion too:
+DCLFDOPEN and DCLPOPEN.  Added these to the irix51 target.  Also had to copy
+the fdopen()-popen() prototype section to ckuusx.c, which has a new reference
+to fdopen() in a workaround for the curses console buffering bug.  makefile,
+ckuusx.c, 30 Dec 2001.
+
+The QNX6 version did not receive a proper herald (it announced itself as
+"unknown version".  Reshuffled #ifdefs in ckuver.h, added display of QNX6
+and NEUTRINO symbols to ckuus5.c, 30 Dec 2001.
+
+Lucas Hart sent in a patch for the VMS problem.  Apparently it was even worse
+than Dave Sneddon had reported: 8.0 couldn't run at all under Batch.  ckvtio.c,
+31 Dec 2001.
+
+A major obstacle to the usability of the FTP client is that certain commands
+don't behave as FTP users expect: CD, DIR, DELETE, MKDIR, etc, which are local
+rather remote, and there are no LCD (etc), USER, or ACCOUNT commands.  We
+could fix this by adding an FTP command-language personality, but file
+management commands can also be remote or local on connections to Kermit
+servers too.  So:
+
+SET LOCUS { LOCAL, REMOTE, AUTO }
+  Sets the locus for unprefixed file management commands.
+  When LOCAL, a REMOTE (or R) prefix is required for
+  to send file management commands to a remote server (e.g. RCD, RDIR).
+  When REMOTE, an L prefix is required to issue local file management
+  commands (e.g. LCD, LDIR).  The word LOCAL can't be used as a prefix
+  since it is used for declaring local variables.
+
+This applies to all types of connections, and thus is orthogonal to SET
+GET-PUT-REMOTE, which selects between Kermit and FTP for remote file-transfer
+and management commands.
+
+The default LOCUS is AUTO, which means we switch to REMOTE whenever an FTP
+connection is made, and to LOCAL whenever a non-FTP connection is made,
+and switch back accordingly whenever a connnection is closed.
+
+Implementation (31 Dec 2001):
+ . None of this is compiled if LOCUS is not defined.
+ . Added XYLOCUS (SET LOCUS) and LOCUS definitions: ckuusr.h.
+ . Override by defining NOLOCUS (which inhibits definition of LOCUS).
+ . Added LOCUS to SET keyword table: ckuusr.c.
+ . Added locus & autolocus variables: ckuusr.c.
+ . Added SET LOCUS parsing and variable setting: ckuus3.c.
+ . Added display of LOCUS setting to SHOW COMMAND: ckuus5.c.
+ . Added automatic locus setting to setlin(): ckuus7.c.
+ . Added automatic locus setting to ftpopen() and ftpclose(): ckcftp.c.
+
+How to catch all the places where a Kermit connection is closed?  Turns out
+we've done this before, when we added the connection log.  So I made
+dologend() take care of locus switching.  But dologend() was not compiled in
+if certain symbols were defined, such as NOLOCAL, or not defined, such as
+CKLOGDIAL.  So I (a) rearranged the #ifdefs so that even if these would
+otherwise have obliviated dologend(), now they leave a piece of it for
+locus-setting; (b) moved the prototype out of #ifdefs; and (c) took all calls
+to it out of #ifdefs.  ckcker.h, ckcfn2.c, ckcmai.c, ckucns.c, ckucon.c,
+ckuus[r347x].c, 31 Dec 2001.
+
+Added locus checking to the following commands: DIRECTORY, CD/CWD, CDUP,
+DELETE, PWD, MKDIR, RMDIR, RENAME.  ckuusr.c, 31 Dec 2001.
+
+Added LDIRECTORY, LCD/LCWD, LCDUP, LDELETE, LPWD, LMKDIR, LRMDIR,
+LRENAME.  ckuusr.[ch], 31 Dec 2001.
+
+Added USER and ACCOUNT commands, which are the same as FTP USER and FTP
+ACCOUNT.  ckuusr.[ch], ckcftp.c, 31 Dec 2001.
+
+Since automatic locus switching could be a big surprise for most people, I
+printed message any time it changed.  ckcftp.c, ckuus[37].c, 31 Dec 2001.
+
+Added help text for the new L commands and filled in missing HELP text for
+SET GET-PUT-REMOTE, CDUP, MKDIR, and RMDIR.  ckuus2.c, 31 Dec 2001.
+
+Changed help text of CD, DIR, etc, for LOCUS.  Changed the help text for
+RCD, RPWD, RDEL, RDIR, etc, to mention that they also work with FTP servers.
+Updated HELP REMOTE for this too.  ckuus2.c, 31 Dec 2001.
+
+Made sure code builds with NOLOCAL, NOLOGDIAL, and NOLOCUS (it does).
+
+The IKSD command, when given with a /USER: switch, sends the user ID to the
+IKSD.  But the SET HOST /USER: command does not, when making a connection to a
+Kermit service.  This makes it impossible to script IKSD interactions using
+only client commands.  Furthermore, even if you include a /PASSWORD switch
+with the IKSD command, it does not send the password.  I added code near the
+bottom of setlin() to do this.  If we have a connection to a Kermit service
+and a /USER: switch was given, then we attempt a REMOTE LOGIN.  If a
+/PASSWORD: switch was not given then if the username is "ftp" or "anonymous",
+we automatically supply a password of user@host; otherwise we prompt for a
+password.  If a /USER: switch was not given, it acts like before.  It all
+works, but it might not be the best way (or place) to do it.  setlin():
+ckuus7.c, 31 Dec 2001.
+
+  NOTE: The above change doesn't help with IKSD /USER:anonymous,
+  the server prompts for password anyway, not sure why.
+
+  NOTE 2: What about secure authentication?  We have to test to see
+  if user was already authenticated before sending the login packet.
+
+Added /opt/kermit and /opt/kermit/doc to info_dir[] list (for Solaris).
+ckuus5.c, 31 Dec 2001.
+
+From Jeff: new Help text for SET TERM FONT (K95 GUI).  ckuus2.c, 1 Jan 2002.
+
+More work on help text for file management commands -- e.g. we can't lump
+the L-commands together with the unprefixed ones; they need separate entries.
+Also: added missing HELP REMOTE PWD, improved the default case (in which
+help text had been omitted for a valid command).  ckuus2.c, 1 Jan 2002.
+
+It seems VMS C-Kermit was pretty much ignoring the -B (force background) and
+-z (force foreground) command-line options.  Fixed in congm(): ckvtio.c,
+1 Jan 2002.
+
+Tested the SET LOCUS business with VMS C-Kermit, which does not have a
+built-in FTP client.  Of course in this case there is no automatic locus
+switching, but SET LOCUS REMOTE works nicely on IKSD connections.
+
+From Jeff:
+ . #ifdef adjustments for LOCUS changes.
+ . SSH KEY CREATE /TYPE:SRP.
+ . Fix \v(serial) to not be 8N2 by default if speed is 0.
+ . Don't let doexit() run if sysinit() hasn't been called first.
+ckuus[r247x].c, 2 Jan 2002.
+
+Made SET BACKGROUND { ON, OFF } do exactly the same as -B and -z options.
+ckuus3.c, 2 Jan 2002.
+
+Updated user-visible copyright dates to 2002 (but still need to do all the
+source-module comments).  ckcmai.c, ckuus[25].c, 2 Jan 2002.
+
+Rearranged #include <sys/time.h> in ckucns.c that was done for IRIX 5.3,
+to avoid conflicts in SV/68 R3v6.  3 Jan 2002.
+
+From Dave Sneddon: Code changes in VMS sysinit() and congm() to work around
+problems in batch, SPAWN'd, etc, and change CTTNAM from TT: to SYS$INPUT:.
+ckcdeb.h, ckvtio.c, 3 Jan 2002.
+
+From Jeff:
+ . Fixed typo in definition of CTTNAM for VMS.  ckcdeb.h
+ . Moved macro definitions for SSHBUILTIN from ckuus3.c to ckuusr.h
+   so they can be referenced in ckuus7.c
+ . Added SSH functionality to SET HOST:
+     SET HOST /NET:SSH /CONNECT hostname [port] /switches
+ . Fixed SET NET TYPE so it won't reject SSH if SSH is installed.
+ . Changes to allow IKSD to continue functioning.  Somehow this minor change
+   to ckcmai.c got lost in one of the back and forth exchanges.
+ . HELP TEXT for UCS2 kverb
+ . Fix a problem in K95 where multiple threads could be attempting to
+   send a telnet negotiation simultaneously.
+ckcmai.c ckcdeb.h ckuus2.c ckuus3.c ckuusr.c ckuusr.h ckuus7.c ckctel.c
+ck_crp.c ckuat2.h ckuath.c, 4 Jan 2002.
+
+From Jeff:
+
+  Peter Runestig complaining that the Telnet Forward X code was corrupting
+  data.  This resulted in a very thorough examination of the telnet module
+  code and a discovery of some rather significant problems.  The root of the
+  problems is the lack of thread safety.  To correct this problem the
+  following was done.
+
+  All code (regardless of module) which outputs telnet commands is placed
+  into a mutex region to ensure that competing output threads do not result
+  in interleaving their output.  This could happen for instance when the
+  forward-x thread is forwarding data and the user changes the window size
+  or sends an AYT or BREAK.  Next the buffer used for input and output
+  processing were identical.  This means that output data could be treated
+  as input or vice versa.  Ugh....
+
+  I also spent some more time cleaning up setlin().  Mostly reorganizing the
+  code into single if (...) blocks so that breaking it up will be easier.
+
+ckctel.c ckuus7.c, 4 Jan 2002.
+
+Updated internal copyright notices.  All modules, 5 Jan 2002.
+
+From Jeff:
+  More of same, plus new makefile target and changes from Spike Gronim
+  for freebsd44+srp+openssl.
+ckcdeb.h ckcnet.c ckctel.c ckuus7.c ck_ssl.c makefile, 5 Jan 2002.
+
+Some minor updates and fixes to SSH and SET SSH help text.
+ckuus2.c, 6 Jan 2002.
+
+Added SET RGB-COLORS for GUI.  ckuusr.[ch], ckuus3.c, 6 Jan 2002.
+
+From Jeff: More Telnet changes, Debug semaphores for K95, etc: ckcdeb.h,
+ckuusr.h, ckuus[r35x].c, ckctel.[ch], ckuath.c, 7 Jan 2002.
+
+Added --xpos:n --ypos:n, SET GUI WINDOW POSITION x y, and changed SET
+RGB-COLORS to SET GUI RGBCOLOR.  Action needs to be filled in (in setguiwin()
+in ckuus3.c), and gui_xpos and gui_ypos need to be defined in cko???.c.
+ckuusr.h, ckuus[r3y].c, 7 Jan 2002.
+
+Added --fontname:name --fontsize:name (and facename as synonym for fontname).
+ckuusr.h, ckuus[7y].c, 7 Jan 2002.
+
+Moved GUI (not OS/2) SET TERM FONT code in ckuus7.c to its own routine,
+setguifont(), in ckuus3.c, and made GUI SET TERM FONT call this routine,
+and also made SET GUI FONT call the same routine.  ckuus[37].c, 7 Jan 2002.
+
+Added --termtype:, --height:, --width:, --user:.  Also added symbols for
+--telnet:, --ssh:, --ftp:, --[remote-]charset, and --password:, but didn't
+fill them in.  --password: is probably not a good idea (but we allow it for
+FTP); the others involve a lot of code-shuffling and reconciliation, which
+I'll try to do when I get a chance (especially the connection ones, which
+can be done as part of the setlin() restructuring).  ckuusr.h, ckuusy.c,
+8 Jan 2002.
+
+Also I tried commenting out the #ifndef KUI..#endif's around SET TERMINAL
+CHARACTER-SET (easier said than done because a crucial #endif was mislabeled).
+Let's see if it compiles & works...  ckuus7.c, 8 Jan 2002
+
+Added FTP [ OPEN ] /NOINIT, meaning don't send REST, STRU, and MODE commands
+upon making an FTP connection.  This allows connection to servers that close
+the connection (or worse) when given these commands (e.g. Linux 2.4 TUX 2.0
+FTP server).  ckcftp.c, 8 Jan 2002.
+
+Looked at adding caller ID support for the ANSWER command:
+
+ . SET ANSWER CALLER-ID { ON, OFF }
+ . SET ANSWER RINGS <number>
+ . \v(callid_xxx) xxx = { date, time, name, nmbr, mesg }
+ . CKD_CID modem capability
+ . Set CKD_CID for modems that have it.
+ . A quick survey shows:
+   - USR V.90:      No (but Jeff says some USRs have it).
+   - V.250:         No
+   - Lucent Venus:  No
+   - USR:           #CID=1 (the ones that have it -- X2?)
+   - Diamond Supra: #CID=1
+   - Rockwell 56K:  #CID=1
+   - PCTEL:         #CID=1
+   - Zoltrix:       +VCID=1
+   - Conexant:      +VCID=1
+ . Since there are different commands to enable caller ID reporting,
+   we need a new field in struct MDMINF.
+ . SHOW MODEM and SHOW DIAL would need updating.
+ . etc etc...
+
+This is all way too much for now so I just did the setting of the \v(callid_*)
+variables.  These are reset at the beginning of an ANSWER command, and then
+set by the ANSWER command if they come in; thus they persist from the time
+they are collected until another ANSWER command is given.  To take advantage
+of autoanswer, the user has to enable it in the modem (all the modems I found
+that support it have it disabled by default), and also has to set the number
+of rings to at least 2.  This can be done with (depending on the modem):
+
+  set modem command autoanswer on ATS0=2#CID=1\{13}
+  set modem command autoanswer on ATS0=2+VCID=1\{13}
+
+and undone with:
+
+  set modem command autoanswer on ATS0=1#CID=0\{13}
+  set modem command autoanswer on ATS0=1+VCID=0\{13}
+
+The variables can be accessed only after the call is answered.  Therefore the
+only way to refuse a call is to answer it, inspect the variables, and then
+hang it up if desired.  Future Kermit releases can do this more nicely (as
+sketched out above.)  Also while I was in the dialing code, I added result
+code VCON (= VOICE), used by several of the newer modems.  These changes are
+untested.  The SET ANSWER command is written but commented out.  ckuusr.h,
+ckcker.h, ckuus[r3].c, ckudia.c, 8 Jan 2002.
+
+From Jeff: fixes to --termtype:, --height:, --width:, --user:, and filling in
+of --rcharset:, which required extracting code from settrm() into a separate
+parse-method-independent remote character-set setting routine.  ckuus[7y].c,
+8 Jan 2002.
+
+From Jeff: More work on TERMINAL CHARACTER-SET code reorganization, and
+reinstatement of SET TERMINAL CHARACTER-SET in K95G.  Also, fix char/CHAR
+warnings in Telnet module.  ckuus7.c, ckctel.c, 9 Jan 2002.
+
+Made SET TERM CHARACTER-SET visible for all builds, including K95G, and filled
+in HELP text for it.  ckuus[27].c, 9 Jan 2002.
+
+Added help text for new extended options.  ckuusy.c, 9 Jan 2002.
+
+Commented out the return(-2) statement at the end of xgnbyte() to make the
+"Statement not reached" errors go away, after checking to make sure that there
+was no path that could fall through to the end.  I'm 99.99% sure there isn't,
+but that doesn't mean that some compilers might not still complain.  ckcfns.c,
+9 Jan 2002.
+
+From Jeff: fix typo in the K95 extended-option help text; add more
+semaphores to network i/o.  ckuusy.c, ckcnet.c, 10 Jan 2002.
+
+Undid ansiisms in set{lcl,rem}charset() declarations.  ckuus7.c, 10 Jan 2002.
+
+Removed a duplicated clause from the install target.  makefile, 10 Jan 2002.
+
+From Jeff: more semaphores.  ckcnet.c, 11 Jan 2002.
+
+Moved references to tmpusrid and tmpstring out of NOSPL #ifdefs -- they can
+be used with NOSPL.  setlin(): ckuus7.c, 13 Jan 2002.
+
+Made a dummy dologend() routine outside of #ifndef NOICP, so we don't have
+to enclose every reference to dologend in #ifdefs.  (I had added a bunch of
+calls to dologend() throughout the code to handle automatic LOCUS switching.)
+ckuus3.c, 13 Jan 2002.
+
+Moved "extern int nettype" outside of NOICP #ifdefs in ckuus4.c for NOICP
+builds.  13 Jan 2002.
+
+Moved a misplaced #ifdef in the VERSION command.  ckuusr.c, 13 Jan 2002.
+
+Did 81 different feature-selection builds on Linux (RH 7.0), all OK after the
+changes listed above for today.  13 Jan 2002.
+
+Added prototypes for set{rem,lcl}charset().  ckcxla.h, 13 Jan 2002.
+
+Added ckcxla.h to dependencies for ckuusy.c.  ckvker.com, 13 Jan 2002.
+
+Made a correction to the HELP SET LOCUS text and supplied a missing comma
+for HELP REMOTE.  ckuus2.c, 13 Jan 2002.
+
+Built OK on HP-UX 11.11 (K&R and ANSI), Solaris 8 (cc), Solaris 2.5.1 (gcc),
+SunOS 4.1.3 (cc and gcc), VMS 7.1 (DEC C, net and nonet), Unixware 7.1.1,
+Tru64 4.0G, HP-UX 10.20 (K&R), AIX 4.3.3, FreeBSD 2.2.8, Slackware 8.0, IRIX
+6.5.13f, IRIX 5.3 (??? Can't tell -- the computer ran out of swap space -- but
+it was OK a few days ago), VMS 5.5-2 (VAX C, UCX + nonet)...  HP-UX 9.05, ...
+
+Some corrections to comments in HP targets from PeterE.  makefile, 14 Jan 2002.
+
+Corrections to prototypes for set{rem,lcl}charset() (VOID, not void) from Jeff.
+ckcxla.h, 14 Jan 2002.
+
+Builds, cont'd...  SINIX 5.42, Red Hat Linux 5.2 on i386, SuSE 7.0 on S/390, 
+Red Hat 7.1 on IA64, QNX 4.25, HP-UX 5.21/WinTCP, ..., 
+
+Dell Coleman <dell@aleph.tum.com> noticed that in AIX, the COPY command always
+says "Source and destination are the same file" when the destination file
+doesn't exist.  This is because in AIX, realpath() fails with ENOENT (errno
+2).  The zfnqfp() code already accounts for this, but evidently not well
+enough.  So I did what I should have done long ago.  zfnqfp() was originally
+accomplished with do-it-yourself code.  Later I added support for realpath(),
+and partitioned the routine into mutually exclusive compile-time sections:
+#ifdef CKREALPATH realpath()... #else do-it-yourself... #endif.  But if
+realpath() failed, there was no recourse to the do-it-yourself code.  Today I
+replaced the #else with the #endif, so the do-it-yourself part is always
+included and is executed if the realpath() call fails.  Built and tested on
+AIX 4.3.3 and Solaris 2.5.1, as well as on Linux with and without the
+realpath() code included.  zfnqfp(): ckufio.c, 16 Jan 2002.
+
+Separated K95 and C-Kermit test version numbers, so C-Kermit can be RC.02
+while K95 is Beta.01.  ckcmai.c, 16 Jan 2002.
+
+Inhibited 0-length writes by conol() and conoll(), since they cause big
+trouble with the AIX 4.3.3 pty driver, e.g. when you have an SSH connection
+into AIX and run C-Kermit there.  ckutio.c, 16 Jan 2002.
+
+Suppressed "Switching LOCUS..." messages from FTP client when it was invoked
+from the command line.  ckcfns.c, 17 Jan 2002.
+
+Dave Sneddon noticed that FOPEN /APPEND gets "?Write access denied" in VMS
+if the file exists.  This is apparently because VMS zchko() does the wrong
+thing.  Commenting out the call zchko() in the VMS case gets past this but
+then the appended part of the file has different attributes than the orignal
+part, e.g.:
+
+  abc  <- original line (horizontal, normal)
+  d    <- appended line (vertical)
+  e
+  f
+
+VMS fopen() takes an optional 4th argument: a series of RMS keyword=value
+pairs.  Kermit doesn't give any.  Experimentation shows that appending to
+a Stream_LF works fine.  That'll be a restriction for now, until somebody
+sends in code to get the RMS attributes of the original file and feed them
+to fopen().  Also need code to fix VMS zhcko() to say whether it's OK to
+append to a file.  ckuus7.c, 17 Jan 2002.
+
+Somebody suggested I could get a working Kermit for Neutrino 2+ by doing the
+QNX6 build on Neutrino itself.  I verified that this can't be done -- at least
+not by me -- since Netutrino 2+ doesn't have a compiler, and we already know
+the version cross-built for it on QNX4 doesn't work.  17 Jan 2002.
+
+From Jeff: SET SSH GSSAPI KEY-EXCHANGE { ON, OFF } parsing, SHOW SSH.
+ckuus3.c, 18 Jan 2002.
+
+PeterE suggested that SET ESCAPE allow 8-bit escape characters because of the
+difficulty in entering Ctrl-\ on European keyboards and the hardship (e.g. to
+EMACS and VI users) of sacrificing another C0 control character.  Like
+everything these days, this turns out to be rather a bigger deal than it would
+seem.  The SET ESCAPE parser calls setcc(), which accepts control characters
+in various formats (literal, ^X notation, or numbers), and gives an error
+return if the value is not 0-31 or 127.  This is changed easily enough to also
+allow numbers between 128 and 255.  But who else calls setcc()?  The commands
+for setting Kermit packet start and end characters.  No big deal, this gives
+people a bit more flexibility in case they need it, but it won't be
+documented.  setcc(): ckuus7.c, 18 Jan 2002.
+
+Since code to display the escape character is scattered all over the place,
+and some of it indexes into an array based on the character value (which would
+now dump core if the escape character was > 128), I put the code in one place,
+a new shoesc() routine in ckuusx.c (which needs to be outside #ifndef NOICP,
+since the CONNECT modules use it even in command-line only builds).  Also
+discovered that this code was indexing into the nm[] array with tt_escape to
+get "enabled" or "disabled", which is no longer appropriate, so fixed this
+too.  ckuusr.h, ckuus[5x].c, 18 Jan 2002.
+
+Made SHOW ESCAPE, SHOW TERM, and the various CONNECT modules call shoesc(),
+and updated HELP SET ESC.  ckuus[25].c, ckucns.c, ck[cuvd9]con.c, 18 Jan 2002.
+
+After all that, it occurred to me that this is a really bad idea for K95,
+with all the confusion about Console code pages, OEM code pages, Windows
+code pages, and Unicode.  But I tried "echo \161" at the K95 prompt and got
+the expected 8-bit character in both the Console version and the GUI, so
+maybe it's OK after all.
+
+Removed the automatic IKSD login code from setlin() since it complicates
+interactive anonymous login.  ckuus7.c, 20 Jan 2002.
+
+An #ifdef clause from Matthew Clarke to avoid "redeclaration of free" error
+when building a curses version of C-Kermit for AIX 2.2.1 on RT PC.  ckuusx.c,
+22 Jan 2002.
+
+Took care of one detail I omitted when adding the 8-bit escape character:
+not stripping the 8th bit before comparing the keyboard char with the escape
+char.  ck[uv]con.c, ckucns.c, 24 Jan 2002.
+
+Started to go through Jeff's changes of the last week but he had run trim -t
+on them, which untabifies, so the diffs were huge.  Retabifying Jeff's files
+only makes matters worse.  So instead of comparing each old and new source
+file in EMACS windows with M-X Compare-Windows like I usually do (which can't
+be told to ignore whitespace), I had to work from the diff -c -b listings.
+In ascending order of size of diffs:
+
+ckcker.h: Add I_AM_SSHSUB definition.
+ckuusr.h: XXLINK and VN_PERSONAL, etc, definitions.
+ckuusy.c: Support for "I Am SSHSUB" invocation.
+ckuus5.c: Support for new K95 directory structure.
+ckcmai.c: Init endianness earlier (K95 TYPE was broken), "I Am SSHSUB" support.
+ckuus7.c: Security #ifdefs, SSH OPEN /PASSWORD, SSHSUB support
+ckcftp.c: <-- SAVE TIL LAST
+ckuus6.c: Add LINK command for K95 on NT.
+ckuus4.c: Support for new K95 directory structure; SSHSUB support
+ckuus3.c: Support for new K95 directory structure; some SSH changes
+ckuus2.c: Changes to SSH related help text, add HELP LINK text
+ckuusr.c: LINK command, SSH OPEN /PASSWORD: /SUBSYSTEM: switches,
+  Pattern-management fixes.
+ckctel.c, ck_ssl.c, ckuath.c, ckcnet.c:
+ Took Jeff's without looking.
+ckuusx.c, ckucns.c, ckucon.c, ckwart.c:
+  My changes from weeks ago that were never picked up.
+
+Built OK on Solaris with gcc and on SunOS with (K&R non-ANSI) cc.
+31 Jan 2002.
+
+Meanwhile, Jeff had made various changes in response to Jaya Natarajan at IBM,
+whose basic complaint was that numerous failure conditions were not being
+detected if the fullscreen file-transfer display was active.  Jeff found that
+this was because big blocks of code were skipped in that case and changed the
+code not to do that, which fixed the reported problems.  But later Jaya said
+that "ftp mget file1 file2" acted like "ftp mget *", so it seemed that Jeff's
+fixes broke file selection.  After taking Jeff's fixes for ckcftp.c, however,
+I still could not reproduce the problem.  ckcftp.c, 31 Jan 2002.  <-- Later,
+it turned out the problem was with IBM's custom FTP server.
+
+Fixed updates that I missed yesterday in ckcftp.c, ckuusr.c.  Moved misplaced
+#ifdef in ckuusy.c breaking nonet builds.  Added #ifdefs to sysinit() for
+nonet builds in ckutio.c.  Ran through build-in-many-configurations script
+in Linux, all builds OK.  1 Feb 2002.
+
+Moved shoesc() definition outside of NOXFER to fix NOXFER builds.
+ckuusx.c, 1 Feb 2002.
+
+Added MYCUSTOM definition alongside KERMRC and changed KERMCL to be the
+same as CKMAXPATH, instead of some random hardwired number.  ckuusr.h,
+1 Feb 2002.
+
+Changed ckcdeb.h to define DIRSEP and ISDIRSEP(), and put #ifndef
+[IS]DIRSEP..#endif around all [IS]DIRSEP definitions in ck[udso]fio.c, so we
+can finally put away the many repeated #ifdef chains when we get around to it.
+1 Feb 2002.
+
+Make VMS zkermini() return 1 on success, 0 on failure, rather than 0 always.
+ckvfio.c, 1 Feb 2002.
+
+Added code to doinit(), just before it goes to execute the init file.  If the
+init file name we are about to open is empty or fails zchki(), substitute the
+customization filename.  For now this code is in #ifdef USE_CUSTOM..#endif,
+which is not defined by default.  It does the trick in Unix and VMS.  Also
+included code from Jeff for K95, but this needs verification and testing.
+Also used DIRSEP and ISDIRSEP() throughout doinit() instead of the long #ifdef
+chains.  ckuus5.c, 1 Feb 2002.
+
+Moved shoesc() prototype from ckuusr.h to ckcker.h so modules that need it
+don't have to include ckuusr.h just for this one thing (example: ckvcon.c).
+1 Feb 2002.
+
+Defined USE_CUSTOM by default, except if NOCUSTOM is defined.  ckuusr.h,
+1 Feb 2002.
+
+Fixed kermit-sshsub code to really enter server mode, and to print
+"KERMIT READY TO SERVE..." so scripts can wait for it.  Also bumped the
+C-Kermit test ID to RC.03 and the K95 one to Beta.02.  ckcpro.w, ckcmai.c,
+2 Feb 2002.
+
+I was thinking about adding SET COMMAND BUFFER-SIZE to let people allocate
+as big a buffer as they wanted at runtime, mainly for defining huge macros.
+Moved the SCMD_blah definitions from ckuusr.h to ckuus3.c, since they aren't
+used anywhere else.  But stopped there since the rest turns out to be a rather
+big deal.  ckuusr.h, ckuus3.c, 2 Feb 2002.
+
+From Jeff, 3 Feb 2002:
+ . Fix an out-of-order modem name in the SET MODEM TYPE table: ckudia.c.
+ . Use SET LOGIN USER and PASSWORD if present. ckcftp.c.
+
+Cody Gould noticed that array declarations had become case sensitive, and
+upper case didn't work.  Diagnosis: misplaced case conversion in xarray().
+Fixed in ckuus5.c, 4 Feb 2002.
+
+SHOW VAR dumps core on \v(sexpression) or \v(svalue) -- failure to check for
+NULL pointer.  I wonder why this didn't happen before (answer: because I was
+doing it on SunOS; now I'm doing it on Solaris).  ckuus4.c, 6 Feb 2002.
+
+I've had several requests for "show var name name name...".  I added this to
+doshow(), such that SHOW VAR works exactly as it did before (if you don't give
+it an arg, it lists all variables; if you give it an arg, it appends "*" to it
+and lists all matching variables) but now you can also give more than one arg
+and it works the same way with each one as it did before if you gave it a
+single item (i.e., "*" is appended, so "show var os cmd" shows all variables
+whose names begin with "os" or "cmd".  You can also freely use pattern
+notation, including anchors.  Hmmm, no, actually it's different in that now
+each includes an implied * before AND after, so "show var version" shows all
+variables whose name contain "version" rather than all variables whose names
+start with it.  ckuus5.c, 6 Feb 2002.
+
+Cody Gould reported that WRITE FILE blah blah \fexec(anything) ... got a
+spurious "File or Log not open" error.  This turns out to be a rather
+pervasive problem -- whenever you use \fexec() it calls the parser recursively
+and this can run roughshod over global variables, such as our innocent little
+x, y, and s.  The fix in this case was to put x and y on the stack.  The same
+thing probably needs doing in about 10,000 other places.  Too bad C isn't
+Algol.  ckuusr.c, 6 Feb 2002.
+
+Minor fix to SHO VAR -- the "^" anchor wasn't working (e.g. "show var ^os").
+ckuus5.c, 6 Feb 2002.
+
+Fixes from Jeff for FTP file-transfer character-set translation in K95 and
+in WIKSD, plus updated K95 SSH help text.  ckcftp.c, ckcfns.c, ckuus2.c,
+7 Feb 2002.
+
+Server has its date set in the past.  Client says "remote dir".  Server sends
+A packet containing old date.  If client has FILE COLLISION UPDATE, it
+rejects the directory listing.  Changed gattr() to only reject real files
+(introduced by F packet), not X-packet material like directory listings.
+ckcfn3.c, 7 Feb 2002.
+
+Up-down arrow keys for command recall.  People have been asking for it for
+years but now it's actually important because of PDAs that don't have Ctrl
+keys.  Would have been trivial except that we use getchar() rather than
+coninc() for reading from the keyboard in Unix so conchk() doesn't help.  In
+fact there are lots of other places where conchk() is used this way and works
+only by accident.  The only reason we never noticed a problem before is that
+characters don't usually arrive from the keyboard that fast.  But when an
+arrow key sends "ESC [ A" all once, the stdin buffer gets some extra stuff in
+it, which getchar() will return next time, but which coninc()/conchk() will
+never see.  So I added a new cmdconchk() routine which, if the keyboard is
+being read with getchar() rather than coninc(), looks at the stdin buffer.
+Unfortunately, however, there is no API for this, nor is there any standard
+way to access the stdin buffer directly.  So first I did it for Solaris.  Then
+to make it portable requires a survey of the headers for every platform.  I
+found four major variations:
+
+  stdin->_r:
+    {Free,Open,Net}BSD, BSDI
+  stdin->_cnt:
+    SunOS, Solaris, HP-UX 5-6, AIX, VMS, SINIX, IRIX 5.3-6.5, DGUX
+    4.2BSD, 4.3BSD, OSF/1..Tru64, QNX4, Unixware 1.0-2.1.0
+  stdin->__cnt:
+    HP-UX 7-11, SCO: OSR5.0.6a, Unixware 2.1.3-7.x, OU8, UNIX 3.2v4.x
+  Subtract read from end pointer (_IO_file_flags defined):
+    Linux (tested on RH 5.2 thru 7.1)
+
+The Linux method is new and different to account for multibyte characters.
+All the others assume character == byte.
+
+For docs: ANSI only, 7-bit only; both application and cursor modes are
+accepted.  Only up and down arrow are handled; left and right arrows cause
+a beep.  ckucmd.c, 8 Feb 2002.
+
+Build-all: Discovered that changing CTTNAM from TT: to SYS$INPUT: in VMS
+(which was done on 3 Jan 2002 to work around problems starting Kermit in
+batch, spawn'd, etc) breaks Kermit on VMS 5.5/VAX (concb() fails with "lacks
+sufficient privilege"; if you enable all privs Kermit starts but then spews
+out a constant stream of BEL characters).  If you put dftty back to "TT:",
+everything is fine -- I have no idea why, so I used #ifdef VMSV70 to decide,
+which is totally crude.  Next I had to find where the boundary really is: VAX
+vs Alpha?  VAX C vs DEC C?  Or between VMS releases?  Built on:
+ . VMS 6.2 Alpha (DEC C) - OK with TT:
+ . VMS 6.2 Alpha (DEC C) - OK with SYS$INPUT: <-- keep this one
+ . VMS 7.1 VAX   (DEC C)
+So the final condition is #ifdef VMSV60.  ckvker.com, ckvtio.c, ckuus5.c.
+
+QNX 6 needed some attention too:
+ . Whoever did the makefile target made the default port "/dev/ser1".
+ . Arrow keys...
+But I gave up on getting arrow keys to work -- it should be just like *BSD,
+but for some reason gcc complains that struct FILE has no _r member, even
+though it does (getchar uses it).
+
+Checked stdio.h on Mac OS X and it looks like the *BSDs.
+
+--- C-Kermit 8.0.201 ---
+
+Removed -g from solaris2xg+krb5+krb4+openssl+shadow makefile target -- it
+was producing a 15MB binary!  makefile, 14 Feb 2002.
+
+Fixed a couple thinkos in "make install": $(DESTDIR) should not have been
+included in the tests for whether INFODIR or SRCDIR were desired.  makefile,
+14 Feb 2002.
+
+(tarball refreshed 16 Feb 2002)
+
+--- C-Kermit 8.0.201 ---
+
+From Jeff: Better seeding of \frandom(): ckcmai.c, ckuus4.c, 18 Feb 2002.
+
+From Jeff: Make arrow keys work in WIKSD, but now also unconditionally
+compile arrow-key code in all versions.  ckucmd.c, 18 Feb 2002.
+
+From Jeff: ckuath.c, ck_ssl.c, ckcnet.c (didn't look).  18 Feb 2002.
+
+Added ORIENTATION command, that lists the various important directories, and
+\flongpathname() and \fshortpathname(), which do path format conversions in
+Windows, and are just synonynyms for \fpathname() elsewhere.  The new functions
+need building and testing in Windows.  ckuusr.h, ckuus[r24].c, 18 Feb 2002.
+
+Changed PWD for Windows only to show both short and long paths (but only if
+they are different; otherwise it behaves as before).  ckuusr.c, 18 Feb 2002.
+
+Changed default Windows prompt to show long pathname. ckuus5.c, 18 Feb 2002.
+
+Updated INTRO command to mention FTP, HTTP, and SSH.  ckuus2.c, 18 Feb 2002.
+
+From Jeff: fixes for typos in GetLongPathName() code: ckuus[r4].c, 22 Feb 2002.
+
+From Jeff: net/auth updates: ckcnet.c, ckuath.c, 22 Feb 2002.
+
+Added -DUSE_FILE__CNT to NCR MPRAS targets, George Gilmer: makefile,
+24 Feb 2002.
+
+From Jeff: Add support for GetLongPathName() in Win95 and NT: ckcdeb.h,
+ckuus[r4].c, 24 Feb 2002.
+
+From Jeff: More fixes for FTP SIGINT, plus fix [M]PUT /MOVE.  ckcftp.c,
+24 Feb 2002.
+
+Fixed an unguarded reference to inserver, gtword(): ckucmd.c, 24 Feb 2002.
+
+Adapted RETRIEVE for use with FTP connections; this one was missed when
+adapting GET, REGET, MOVE, etc.  ckuus6.c, ckcftp.c, 24 Feb 2002.
+
+Added special COPYRIGHT command text for the free version of WIKSD.
+ckcmai.c, ckuusr.c, 24 Feb 2002.
+
+C-Kermit, when in CONNECT mode and given the <Esc-Char>U sequence, would
+unconditionally close the connection if it was a network connection.  This
+is bad when Telnetting to a modem server.  I added to code to prevent this
+in the RFC2117 TELNET COMPORT case but I'm not sure how to exend this to the
+general case (or whether it would be a good idea).  ckucns.c, 24 Feb 2002.
+
+During file transfer, chktimo() calls ttgspd() for every packet, which clearly
+doesn't make sense on network connections, especially since on Telnet COMPORT
+connections it results in a network speed query for every packet.  Rearranged
+the code so this happens only on true serial-port connections.  ckcfn2.c,
+24 Feb 2002.
+
+From Jeff: Fix reversed ANSI/non-ANSI function declarations clauses in
+ckcftp.c, 26 Feb 2002.
+
+Changed Unix CONNECT module to call kstart() only when it has a chance of
+doing anything (i.e. a Kermit packet has been partially detected, or the
+packet start character just came in), rather than unconditionally on every
+incoming character.  ckucns.c, 8 Mar 2002.
+
+FTP PUT /SERVER-RENAME:, /RENAME-TO:, /MOVE-TO: were sticky.  Patch: In
+ckcftp.c, near the top of doftpput(), add the lines marked with "+":
+
+    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(). */
+
+ckcftp.c, 26 Mar 2002.
+
+\fday() and \fnday() were broken for dates prior to 17 Nov 1858.  Fixed in
+fneval(): ckuus4.c, 28 Mar 2002.
+
+From Jeff:
+ . New calling convenion for demoscrn(): ckucmd.c, ckuusx.c
+ . Fix for host-initiated 80/132 col screen mode change.  ckuus7.c.
+ . New \v(desktop) variable: K95 user desktop directory, ckuusr.h, ckuus4.c
+ . New \v(rfc2717_signature) var: Telnet Com Port, ckuusr.h, ckuus4.c
+ . Uncomment "not-reached" return(-2) in xgnbyte(): ckcfns.c
+ . New dates: ckcmai.c.
+ . Telnet Com Port fixes: ckutio.c
+ . SET PRINTER fixes for K95: ckuus3.c
+ . Session limit adjustments: ckuus3.c
+ . New directory layout for K95 (TAKE, ORIENT): ckuusr.c
+ . Fixes for Telnet Com Port, recycling SSH connections: ckuusr.c
+
+From me, not picked up by Jeff previously:
+ . kstart() speedup: ckucns.c.
+
+1 Apr 2002.
+
+---K95 1.1.21---
+
+From Jeff, 4 Apr 2002:
+ . More fixes for Telnet Com Port: ckuus4.c, ckudia.c, ckutio.c, ckcnet.c:
+   . network connections will check for carrier detect if SET
+     CARRIER-WATCH is ON.   This could have a potential conflict if
+     the option is negotiated and the carrier is off, but the site
+     requires login.
+   . modem hangup message generated since the dial module did not
+     believe that network modems could be reset with a DTR drop.
+ . Version number adjustments: 8.0.203, 1.1.99: ckcmai.c.
+ . Security: ck_ssl.[ch], ckuath.c.
+
+---C-Kermit 8.0.203---
+
+From Jeff, 6 Apr 2002:
+ . Fix typo in HELP REMOTE HOST: ckuus2.c.
+ . More Telnet Com Port fixes: ckctel.c, ckcnet.c, ckudia.c, ckutio.c
+
+From Jeff, 9 Apr 2002:
+ . Fix autodownload problem: ckcfn[2s].c.
+
+Chiaki Ishikawa reported that in Linux (two different kinds), if you choose
+hardware parity, CONNECT, then escape back, the speed can change.  I tracked
+this down to the following statement in ttvt():
+
+	tttvt.c_cflag &= ~(IGNPAR);	/* Don't discard incoming bytes */
+
+Somehow execution of this statement corrupted the speed words of the termios
+struct, which are entirely separate words that are nowhere near the c_cflag
+member.  Anyway, the statement is wrong; it should be:
+
+	tttvt.c_cflag |= IGNPAR;	/* Don't discard incoming bytes */
+
+Fixing it cured the problem; don't ask me why.  ckutio.c, 9 Apr 2002.
+
+From Jeff:
+  fixes the problem reported by robi@hastdeer.com.au.  The request to
+  enter server mode was received while we were entering server mode.
+  But the server was waiting for the response to REQ_STOP sent to the
+  client.  Therefore, we weren't quite in server mode yet and the
+  request to enter server mode was rejected.  A check for the sstate
+  value solves the problem.  ckctel.c, 10 Apr 2002.
+
+Chiaki Ishikawa (CI) discovered the real cause for the speed changing problem.
+I was setting the IGNPAR bit in the wrong flag word: it should have been
+c_iflag instead of c_oflag, silly me.  Fixed in ttvt() and ttpkt(): ckutio.c.
+I also did a thorough census of all the termio[s] flags to ensure each was
+applied to the right flag word -- they were, IGNPAR in the HWPARITY case was
+the only mistake.  CI also discovered that the speed words in the Linux
+termios struct are not used at all -- the speeds are encoded in an
+undocumented field of c_cflag, which explains the problem.  10 Apr 2002.
+
+Any use of \{nnn} character notation in a macro definition, loop, or other
+braced block caused an "unbalanced braces" parse error.  The backslash in this
+case is not quoting the open brace; it's introducing a balanced braced
+quantity.  Special-cased in getncm(): ckuus5.c, 12 Apr 2002.
+
+The semantics of "if defined \v(xxx)" were changed in 8.0 to avoid obnoxious
+error messages when xxx was not a built-in variable (see notes of 19 Nov
+2000), such that "if defined \v(xxx)" would always succeed if there were such
+a variable, even if it had no value.  The behavior that is documented in the
+book (and also in ckermit70.html) and that we had in versions 6 and 7, was
+that IF DEFINED \v(xxx) would fail if \v(xxx) was defined but had an empty
+value OR if it was not defined, and would succeed only if it was defined and
+had a value.  Fixed in boolexp(): ckuus6.c, 12 Apr 2002.
+
+What about \function()s?  IF DEF \fblah() presently succeeds if the function
+exists; you don't even have to give arguments.  I think this behavior is more
+useful than if I required valid arguments and then evaluated the function --
+you can do that anyway with 'if not eq "\fxxx(a,b)" "" ...'  Of course this
+argument applies to "if def \v(xxx)" too, except that the current behavior is
+consistent with the 7.0 behavior, so there is no need for a change.
+
+Kent Martin discovered that if a macro contains a LOCAL statement for a
+variable whose name is the same as, or a unique left substring of, the macro's
+name, then undefining the local variable makes the macro disappear:
+
+  define DateDiff {
+    echo {DateDiff(\%1) executing...}
+  }
+  define Kent {
+    do DateDiff {2}
+    local date
+    assign date {}
+    do DateDiff {3}  <-- This fails (A)
+  }
+  do DateDiff {1}
+  do Kent
+  do DateDiff {4}    <-- So does this (B)
+
+The first part of the problem is that "assign date {}" called delmac with
+exact=0, so delmac evidently deleted first macro whose name started with
+"date" -- and since the only one was DateDiff, that's the one that was
+deleted.  Fixing this (change "delmac(vnp,0)" to "delmac(vnp,1)" in dodef())
+got us past A.  The second part was making the same fix to the delmac()
+call in popclvl().  ckuus[56].c, 13 Apr 2002.
+
+The INPUT command ignored the parity setting, thus SET PARITY EVEN,
+INPUT 10 "login:" didn't work.  Fixed in doinput(): ckuus4.c.  Also fixed a
+bogus #ifdef COMMENT section that messed up the block structure of the module
+and therefore EMACS's indenting.  18 Apr 2002.
+
+Added sco32v500net+ssl and Added sco32v505net+ssl targets, from Scott Rochford
+at Dell (not sure yet if they work).  Makefile, 19 Apr 2002.
+
+From Jeff, 22 Apr 2002:
+ . Added "darkgray" color and made "dgray" an invisible synonym: ckuus3.c.
+ . Fix carrier sense on Telnet Com Port immediately after dial: ckudia.c.
+ . Change krb5_des_blah() arg list: ckutio.c.
+ . Fix ttgmdm() for Telnet Com Port: ckutio.c.
+ . Fix tthang() return code: ckutio.c.
+ . Add aix43gcc+openssl target: makefile.
+
+From Jeff, 25 Apr 2002:
+ . Fix SET GUI keyword table: ckuus[37].c.
+ . A final fix to Telnet Com Port: ckctel.c, ckcnet.c.
+
+From Jeff, 26 Apr 2002:
+ . Another final fix to Telnet Com Port: ckctel.c, ckudia.c.
+
+From Jeff, 27 Apr 2002:
+ . separate the wait mechanism for TELNET SB COMPORT synchronous messages
+   from the asynchronous TELNET SB COMPORT MODEMSTATUS messages: ckctel.[ch]
+ . fix debug messages in Certificate verify functions: ck_ssl.c, ckcftp.c.a
+
+Frank, 27 Apr 2002:
+ . Fixed VMS zgetfs() to fail when file doesn't exist: ckvfio.c.
+ . Fixed UNIX zgetfs() to check for null or empty arg: ckufio.c.
+ . Added #include <time.h> for time() call: ckcmai.c.
+ . Add casts to args in tn_wait() calls: ckctel.c.
+
+SINIX-P 5.42 (Pyramid architecture) makefile target from Igor Sobrado.
+makefile (no source-code changes), 1 May 2002.
+
+From Jeff, 5 May 2002,
+ . Fix some "unknown host" messages: ckcftp.c.
+ . Add more casts to tnc_wait() calls: ckudia.c.
+ . Improvements to SHOW SSH, SHOW GUI: ckuus3.c.
+ . Fixes to SET COMMAND { WIDTH, HEIGHT }: ckuus3.c.
+ . Updates to ck_ssl.[ch], ckctel.c, ckcnet.c.
+
+Fixed the erroneous setting of ssh_cas during switch parsing rather than
+after cmcfm() in setlin(): ckuus7.c, 5 May 2002.
+
+setlin() decomposition (2300 lines), Part One: 
+
+ . Copied a big chunk from the end of setlin(), beginning with net directory
+   lookup, but only the network-specific and common parts, to a new routine,
+   cx_net(), 900 lines.
+
+ . Extracted many repetitious lines of error-message code from cx_net()
+   to a new routine, cx_fail().  Error messages are stored in slmsg, and
+   also printed but only if we were not called from a GUI dialog (and
+   QUIET wasn't set, etc etc).  Any adjutments in this policy can now be
+   made in one place.
+
+ . I put a call to cx_net() in setlin() just before all the code it replaced.
+   It works for TELNET and SET HOST /TELNET.
+
+ . Built with mkwatsol-k5k4ssl; after a couple fixes it builds OK and makes
+   Kerberized connections OK.
+
+ . Copied the serial-port and common parts of the setlin() post-cmcfm()
+   code to another new routine, cx_serial(), about 275 lines.  Fixed
+   messages not to come out when called from GUI dialog, etc.  Inserted
+   a call to cx_serial() at the appropriate spot in setlin().  Tested
+   serial connections on watsun with "set line /dev/ttyh6", works OK.
+
+ . Removed all the code from setlin() that was copied to cx_*().  This slims
+   setlin() down to 1120 lines.  Tested regular Telnet, Kerberized Telnet, and
+   serial connections again, all OK.  The Unix version of the SSH command is
+   OK too.
+
+setlin() deconstruction, Part Two:
+
+Now that we have the common network and serial connection pieces moved out of
+setlin(), we still need to move out the little code snippets for each network
+type that take place between command confirmation and the common code we just
+replaced.   As far as I can tell, this needs doing only for SSH.  The code
+labeled "Stash everything" copied to cx_ssh() but I didn't remove the original
+code since I can't test this.  I think I'm done -- maybe I'm overlooking
+something but I don't know what...  First we need to test the heck out of it
+in all command-line versions (K95 and C-Kermit).  Then to use this from
+the GUI, see the calling sequences for cx_serial(), cx_net(), and cx_ssh():
+
+ . For serial or TAPI connections, the GUI should call cx_serial().
+ . For SSH connections, it should call cx_ssh() and then cx_net().
+ . For all other network connections, just calls cx_net().
+
+ckuus7.c, Cinco de Mayo de 2002.
+
+New ckuus7.c from Jeff, 8 May 2002.  Merge cx_ssh() into cx_net().  Also: I
+had made line[] an automatic variable, since the global line[] buffer is used
+by almost every parsing routine in C-Kermit to hold string fields between
+parsing and execution but Jeff says he found that some code somewhere depended
+on line[] containing the hostname after setlin() was finished.
+
+From Jeff, 10 May 2002:
+ . Fix SET SSH STRICT-HOST-CHECKING parse: ckuus3.c.
+ . Add prototypes for cx_net() and cx_serial(): ckuusr.h.
+ . Add ANSI versions of cx_net() and cx_serial() declarations and supply a
+   missing parameter in the cx_serial() invocation, change SSHCMD cx_net()
+   invocation to new form.
+
+From Jeff, 16 May 2002:
+ . ANSI strictness changes: ck_ssl.[ch]
+ . New DIALER command: ckuusr.[ch]
+ . Correction to how -0 turns off autodownload: ckuusy.c
+ . Prototypes for GUI menu action functions: ckuusr.h.
+ . Replace setting of GUI-action variables by function calls: ckuus[3457x].c
+ . Fix FTP -z switch parsing: ckcftp.c.
+ . Fix SET HOST testing of setlin() return code: ckuus3.c
+
+From Jeff, 18 May 2002:
+ . Allow half-size GUI fonts: ckuus[35y].c.
+
+Fixed setguifont() to parse fractional font sizes and round to nearest half
+point.  ckuus3.c, 18 May 2002.
+
+For GUI, wrote front ends for getyesno(), readtext(), and readpass():
+
+ . uq_ok() prints text and gets Yes/No, OK/Cancel, or just OK response.
+   This replaces getyesno() and can also be used for alert or help boxes.
+
+ . uq_txt() prints text and gets a single text response.  Replaces
+   readtext() and readpass().
+
+ . uq_mtxt() is like uq_txt() but allows multiple text fields.  Replaces
+   any combination of readtext() and readpass().
+
+Obviously the #ifdef KUI portions of the uq_blah() routines need filling in.
+ckuusr.h, ckuus3.c, 18 May 2002.
+
+Converted selected getyesno() calls to uq_ok(): ckcftp.c, ckuus3.c, ckuus6.c.
+Some were not converted because it was inappropriate, e.g. DELETE /ASK; others
+because they're in Jeff's code.  The most interesting conversions are in the
+DIAL command when DIAL CONFIRMATION is ON.  Here there is a dialog for each
+phone number asking if it's OK (ug_ok()) and if not, asking for a replacement
+(uq_txt()); seems to work fine in C-Kermit.  All the candidates for uq_mtxt()
+are in Jeff's code.  18 May 2002.
+
+From Jeff: Convert remaining getyesno/readtext/readpass calls to uq_blah()
+so they can be GUI dialogs.  ckuus[37].c, ckcftp.c, ckuath.c, ck_ssl.c,
+21 May 2002.
+
+Added KCD command = CD to symbolic directory name (EXEDIR, COMMON, APPDATA,
+TMPDIR, etc etc).  ckuusr.h, ckuus[r25].c, 21 May 2002.
+
+From Jeff, 28 May 2002:
+ . --title: commandline option: ckuusr.h, ckuusy.c
+ . Fix some #includes, move some declarations: ckcfns.c
+ . Change K95 version from Dev.00 to Beta.01
+ . ASK[Q] /GUI: ckuus6.c.
+ . Various GUI screen updates and #ifdefs: ckuus7.c
+ . Add missing cx_net() calls to new setlin() for file SuperLAT..: ckuus7.c
+ . Updated uq_*() routines for GUI dialogs: ckuus3.c.
+
+Added GETOK switches (/TIMEOUT for all; /POPUP and /GUI for K95G):
+ckuus6.c, 29 May 2002.
+
+Added HELP SET GUI text.  ckuus2.c, 29 May 2002.
+
+From Jeff:
+ . Another K95-specific #include for ckcfns.c.
+ . More items for K95G Actions menu.
+ . Change K95G Locus switching to call setlocus() rather than set variable.
+ . Ditto for several other variables now settable from Actions menu.
+ . Fix SET HOST /NET:SSH status code so IF SUCCESS works.
+ . Fix SHOW SSH port-forwarding.
+ckcfns.c, ckuus[r367].c, ckcftp.c, ckcmai.c, 30 May 2002.
+
+Changed SET LOCUS to have a new value, ASK, corresponding to new autolocus
+value of 2, K95G only.  Changed setlocus() to not do anything if the new and
+old loci are the same, otherwise to invoke a GUI dialog in K95G if autolocus
+is 2, and also to handle any text messages.  Changed SHOW COMMAND to show ASK
+value for SET LOCUS.  Rewrote HELP SET LOCUS.  ckuusr.[ch], ckuus[23].c,
+ckcftp.c, 30 May 2002.
+
+Add a missing space to Locus popup, and fix Jeff's version of the code to
+compile in C-Kermit.  ckuusr.c, 31 May 2002.
+
+From Jeff, for K95 GUI, 6 June 2002:
+ . Force some GUI popups to be in foreground: ckuus3.c.
+ . Fix SHOW TERM font display: ckuus5.c.
+ . Update K95 version numbers and date (4 June 2002): ckcmai.c.
+ . Add note about encrypted private keys vs scripts to HELP SET AUTH: ckuus2.c.
+ . Fix SET HOST for DECnet: ckuus7.c.
+
+--- K95 2.0 ---
+
+From Jeff, 7 June 2002:
+ . Fix some #ifdefs for Unix builds (locus, dial, etc): ckuus7.c
+ . Add gui_resize_scale_font() prototype: ckuus3.c
+ . Add some missing SET GUI commands: ckuus3.c
+ . Update version numbers: ckcmai.c
+
+--- K95 2.0.1 ---
+
+From Jeff, 11 June 2002:
+ . Conditionalize Locus-switching popup text for GUI/Console: ckuusr.c.
+ . Fix the SRP_installed_as_server() function.  The new API returns TRUE even
+   if the SRP config and password files cannot be found.  Went back to the old
+   API.  This bug affects C-Kermit 8 when built with SRP as well as 1.1.21
+   through 2.0.1.  Since iksdnt.exe has not been shipped yet I fixed it and
+   uploaded a new non-beta build of it.  ckuath.c.
+
+From Jeff, 12 June 2002:
+ . Fix SSH AGENT ADD: ckuusr.c.
+ . Fix --facename: option to not fail if name unknown: ckuusy.c.
+ . Fixes for OpenSSL 0.9.7 and OpenBSD 3.1: ck_ssl.c.
+ . Fix SET AUTH TLS VERIFY NO to prevent a dialog but still a warning if
+   SET AUTH TLS VERBOSE ON is set: ck_ssl.c.
+ . Fix FTP code to verify the hostname as specified by the user and not
+   the hostname discovered by the reverse DNS lookup.  For example,
+     FTP OPEN kermit.columbia.edu
+   should produce a dialog because that name is not in the certificate
+   even though ftp.kermit.columbia.edu (the reverse DNS name) is:  ckcftp.c.
+
+Add support for Solaris 9 and NetBSD 1.6.  makefile, ckuver.h, ckcdeb.h,
+13 Jun 2002.
+
+Discovered that Solaris 9 wants to hide the members of struct FILE, and
+enforces this for 64-bit builds.  They offer some functions like __fbufsize()
+to get the info, but not the info we need for reading escape sequences (the
+_cnt member).  Let's hear it for political correctness.  Created new solaris9g
+(32-bit) and solaris9g64 (64-bit) targets.  Sorry, no arrow keys in 64-bit
+mode.  Also no more direct access to sys_errlist[]; must use strerror().
+makefile, ckucmd.c, 13 Jun 2002.
+
+Added solaris9g+openssl+zlib+pam+shadow, which in turn required adding
+solaris2xg32+openssl+zlib+pam+shadow, needed for gcc 3.1 in which you have
+to specify 32-bit.  Fails for some mysterious reason in link step
+(can't find libssl.so.0.9.6 even though it's there).  makefile, 13 Jun 2002.
+
+Solaris 8 empty socket problems again -- tthang() times out, subsequent
+tcsetattr() calls do horrible things.  Added a bandaid to ttclos(): don't
+call tcsetattr() any more if hangup timed out.  ckutio.c, 14 June 2002.
+
+Gerry B reported the bandaid got us bit farther but Kermit still disappears.
+Added code to reassert the alarm signal handler, since it is likely that
+Solaris has become stricter about this since last time I looked.  (Later
+Gerry reported back that this did the trick -- C-Kermit now exits normally
+and releases the lockfile).  ttclos(): ckutio.c, 17 Jun 2002.
+
+If you use Kermit to copy a file to a destination file that already exists and
+is longer than the source file, the destination file is not truncated.  I had
+mistakenly assumed that setting O_CREAT in the open() call in zcopy() would
+create a new copy of the file.  Fixed by also setting O_TRUNC.  ckufio.c,
+17 Jun 2002.
+
+Updated HELP INPUT and MINPUT text to explain 0 and -1 timeout values, and
+HELP DIAL to explain about entering CONNECT mode automatically.  ckuus2.c,
+17 Jun 2002.
+
+Got rid of client-side "Press the X or E key to cancel" message when giving
+a REMOTE command if QUIET is set or if XFER DISPLAY is NONE.  ckuus7.c,
+17 Jun 2002.
+
+From Jeff 25 Jun 2002:
+ . Add SUN terminal type: ckuusr.h, ckuus[57].c.
+ . Add GUI file transfer display: ckcker.h, ckuus[47x].c.
+ . Changes to allow C-Kermit to build with OpenSSL 0.9.7.  Current
+   C-Kermit code is designed to compile with 0.9.6 and earlier.  To
+   compile with 0.9.7 you must specify -DOPENSSL_097.  This avoids
+   missing symbols in the DES library.  The functions in OpenSSL were
+   renamed in 0.9.7 to avoid link time conflicts with Kerberos 4.
+   ckufio.c ck_crp.c ckuath.c ck_ssl.h ck_ssl.c, makefile.
+
+From Jeff 26 Jun 2002:
+ . apparently the SSL Passphrase Callback function was not converted
+   from readpass() to uq_txt()
+ . FTP Authentication failure errors were not being reported to the
+   user.  So a failure would appear to be a successful completion
+   unless FTP DEBUG was ON.  Now the message is reported unless
+   the QUIET flag is set.
+ck_ssl.c, ckcftp.c.
+
+SET TRANSFER MODE MANUAL didn't work for FTP; fixed in putfile() and getfile():
+ckcftp.c, 1 Jul 2002.
+
+Changed debug log for FTP to log "FTP SENT" and "FTP RECD" for protocol
+messages, just like we do for Telnet, to make it easy to grep them out of
+the log.  ckcftp.c, 1 Jul 2002.
+
+In FTP MGET /UPDATE, equal times spuriously caused download.  doftpget() was
+misinterpreting chkmodtime()'s return code.  ckcftp.c, 3 Jul 2002.
+
+In FTP MGET /RECOVER, recovery is skipped if the local file is newer than
+the remote.  This would seem to make sense, but when a download is
+interrupted, the partial file never gets the date of the remote file, so
+the partial file is always newer, and recovery never works.  Fixed in
+recvrequest() by commenting out the date check.  ckcftp.c, 3 Jul 2002.
+
+A better way to fix the previous problem is to always set the file date from
+the server and then only allow /RECOVER to work when the dates are equal.
+But that's not possible because MDTM is not implemented universally, and it
+conflicts with how Kermit currently works, namely that FTP DATES are OFF by
+default.  Also, checking dates prevents [M]GET /RECOVER from working with
+files that were incompletely downloaded by some other FTP client.
+
+In FTP MGET /RECOVER <wildcard> <wildcard> ..., the first file in each group
+is always downloaded.  Diagnosis: Kermit sends "TYPE A" prior to NLST (as it
+must).  Then when it sends its first SIZE command, it's still in ASCII mode,
+so the server sends the "ASCII size" rather than the binary size, which does
+not agree with the size of the local file (which was downloaded in binary
+mode), so recovery is always attempted even when the files are identical.  The
+TYPE A command is sent by initconn().  After the remote_files() call, we have
+to change the type back to the prevailing type before sending the first SIZE
+command.  Fixed in cmdlinget() and doftpget(): ckcftp.c, 3 Jul 2002.
+
+In FTP MGET /EXCEPT:<pattern> used with SET XFER DISPLAY brief, files that
+are skipped just say ERROR instead of saying why they were skipped.  Fixed
+in doftpget(): ckcftp.c, 3 Jul 2002.
+
+Added EXIT to top-level HELP text.  ckuus2.c, 13 Jul 2002.
+
+Strip braces in REINPUT n {string}.  ckuusr.c, 13 Jul 2002.
+
+Added /QUIET switch to ASK-class commands.  This means not to print any error
+messages when an ASK-class command times out waiting for a response.  Made
+sure that when a timeout occurs, the command fails.  Also made sure the
+c-Kermit prompt doesn't write over the ASK prompt if ASK times out.  Also
+fixed ASK, when it times out, not to return -9, which it did in one case,
+which causes a command-stack dump.  ckuus[267].c, ckucmd.c, 13 Jul 2002.
+
+Fixed SET FILE INCOMPLETE help text, which said that both KEEP and AUTO were
+the default.  ckuus2.c, 13 Jul 2002.
+
+If you SET FTP DEB ON and then turn it OFF, the MGET temp file is still kept.
+Fixed by getting rid of ftp_knf variable and using ftp_deb to control whether
+temp file is deleted (ftp_knf was being set from ftp_deb anyway, but then
+wasn't being reset by SET FTP DEB OFF).  ckcftp.c, 13 Jul 2002.
+
+If an FTP transfer was in progress but the FTP connection drops and automatic
+locus switching is enabled, the locus does not change; thus (for example) a
+subsequent DELETE command makes Kermit send a REMOTE DELETE packet on stdout.
+Fixed in lostpeer(): ckcftp.c, 13 Jul 2002.
+
+For docs: FTP CD with no arg might not be accepted by the server; e.g. the
+Kermit FTP server says "501 Invalid number of arguments".
+
+The FTP module never handled SET INCOMPLETE.  Fixed in doftprecv2().  ckcftp.c,
+13 Jul 2002.
+
+When FTP DATES is ON, we set an incoming file's date only if the file was
+received successfully.  Changed the code to set the file's date even if it was
+received only partially (assuming we can get the date from server).  ckcftp.c,
+13 Jul 2002.
+
+Suppose we were doing FTP MGET /UPDATE from a server directory of 100,000
+files.  Kermit would send a SIZE command for every file unconditionally.  On
+some connections, e.g. to the Red Hat Rawhide server, each one could take up
+to 30 seconds.  That would be 3 million seconds = 34 days.  Don't send a SIZE
+command during the selection phase unless a /SMALLER or /LARGER selector was
+given.  Once the file is selected, send a SIZE command only if one hadn't been
+sent for that file already.  ckcftp.c, 13 Jul 2002.
+
+Made [M]GET and [M]PUT /UPDATE switch imply FTP DATES ON, since they didn't
+work unless it was.  ckcftp.c, 13 Jul 2002.
+
+Added FTP [M]GET /DATES-DIFFER, which is like /UPDATE except it selects files
+that are newer or older, rather than only newer.  This allows updates from
+sources where files might be rolled back to earlier versions.  It's a bit
+dangerous if you use it without knowing what it's for, since it allows older
+files to overwrite newer ones.  (Code is also in place for [M]PUT
+/DATES-DIFFER, and it works, but I commented it out because it's either
+useless or dangerous since when uploading, you can't set the the file dates
+when they are arrive on the server.)  ckcftp.c, 13 Jul 2002.
+
+Changed chkmodtime() to remember if MDTM fails on a particular connection
+because it's an unknown command (500, 502, or 202), and if so, not to ask
+again.  ckcftp.c, 13 Jul 2002.
+
+With this last change, I think it's safe to change the default for FTP DATES
+from OFF to ON.  ckcftp.c, 13 Jul 2002. 
+
+Increased max number of /EXCEPT: patterns from 8 to 64 for file transfer (not
+necessarily for other things).  This is now a compile-time symbol NSNDEXCEPT.
+ckcker.h, ckcmai.c, ckclib.c, ckcfns.c, ckcftp.c, ckuus[rx].c.  13 Jul 2002.
+
+Fixed FTP MGET to not send SIZE command when there is a name collision and
+FILE COLLISION is DISCARD, even if /SMALLER or /LARGER were also specified.
+ckcftp.c, 15 Jul 2002.
+
+MGET fails if no files were transferred, even if the reason is that no files
+met the selection critieria: /COLLISION:DISCARD, /UPDATE, /SMALLER, etc.
+Changed MGET to succeed in that case.  domget(): ckcftp.c, 16 Jul 2002.
+
+Big problems with canceling MGET; Ctrl-C cancels the current file, but we
+don't break out of the file loop, we just go on to the next file.  Worse, if
+we're executing a command file that has a series of MGETs, Ctrl-C doesn't
+break us out of the command file.  Fixed by making failftprecv() and
+failftprecv2() "chain" to the main SIGINT handler, trap().  This is fine in
+Unix, but I'd be really surprised if it works in K95 so I put it in #ifndef
+OS2.  Ditto for MPUT: Added the same treatment to failftpsend() and
+failftpsend2().  Ditto for cmdcancel().  To adapt to K95, search for "TEST ME
+IN K95" (5 places).  ckcftp.c, 16 Jul 2002.
+ 
+Fixed previous fix to account for the fact that failftpblah() can be called
+not only upon Ctrl-C, but also if transfer interrupted with X or Z.
+ckcftp.c, 16 Jul 2002.
+
+Yesterday's fixes revealed another problem: Interrupt MGET with Ctrl-C, start
+another MGET, and the file list is total garbage.  Diagnosis: secure_getc()
+and secure_getbyte() use internal static buffer pointers.  The only way they
+ever get reset is when the data connection is closed by the server, so if you
+interrupt a GET, the pointers are not reset and the next network read (e.g. of
+an NLST response) returns whatever junk was lying around in the old buffer.
+ckcftp.c, 17 Jul 2002.
+
+FTP MGET temp file is kept only if FTP DEBUG is ON.  Changed FTP module to
+also keep it if the regular debug log is active.  ckcftp.c, 17 Jul 2002.
+
+Fixed version test in ckermit.ini: should be 6 digits, not 5.  17 Jul 2002.
+
+Changed C-Kermit version number to 8.0.205 so scripts can test for the
+recent changes.  ckcmai.c, 18 Jul 2002.
+
+---8.0.205---
+
+SET FILE COLLISION UPDATE would unset FTP DATES due to a typo in the recent
+changes.  ckcftp.c, 21 Jul 2002.
+
+FTP [M]GET /DATES-DIFFER really should have been a collision option.  Added
+this option (implemented for FTP only) to both SET FTP COLLISION and the
+FTP [M]GET /COLLISION: table, so this way if you have lots of [M]GETs, you
+don't have to put /DATES-DIFFER on each one.  ckcker.h, ckcftp.c, 21 Jul 2002.
+
+"FTP MGET a* b* c*" would fail to get any c*'s if no b*'s existed.
+ckcftp.c, 21 Jul 2002.
+
+From Jeff, 22 Jul 2002:
+ . Beginnings of Ann Arbor Ambassador terminal emulation for K95;
+   ckuus[57].c, ckuusr.h.
+ . Bump K95 version number to 2.0.2: ckcmai.c
+
+Added -DCK_PAM -DCK_SHADOW to all Solaris targets, 2.6 and above.  makefile,
+23 Jul 2002.
+
+Discovered that CK_SCRIPTS path search for TAKE files was #ifdef'd out
+except for K95.  Fixed in ckuusr.c, 25 Jul 2002.
+
+From Jeff: changes to support K95 italics: ckuus[57].c,  25 Jul 2002.
+
+Fixed path search for TAKE to not search the CK_SCRIPTS path if the filespec
+contains any directory or path parts.  Added a new function to check for
+this:  int hasnopath(filespec) in ckucmd.c: 26 Jul 2002.
+
+Update HP-UX build instructions from PeterE: makefile, 26 Jul 2002.
+
+Commented out "const" from struct pam_message declarations because it
+causes "initialization type mismatch" warnings.  ckufio.c, 26 Jul 2002.
+
+Suppose you have a network directory containing a listing for host "foo":
+
+  foo tcp/ip foo.bar.com
+
+Then in K95 you give a command "set host /network-type:ssh foo".  This
+results in the directory lookup replacing the "ssh" network type with TCP/IP,
+and making a Telnet connection.  Fix attempted at about line 8625 of ckuus7.c
+in cx_net(); needs testing in K95.  26 Jul 2002.
+
+FTP Password: prompt in Unix was not allowing editing.  The code looked right;
+I put in some debugging and suddenly it worked.  Took out the debugging and
+it still worked.  Maybe I dreamed it.  Anyway, I fixed the "FTP SENT" debug
+log entry to not record the password, and removed a redundant section above
+to log the same thing, but prior to any charset conversion.  ckcftp.c,
+27 Jul 2002.
+
+From Jeff, 28 Jul 2002:
+ . Fix typo in initxlist(): ckcmai.c.
+ . Fix typo in Friday's set-host fix: ckuus7.c.
+ . Move parsing of --height/width command-line args after prescan(): ckuusy.c.
+
+Added invisible top-level SITE and PASSIVE commands for FTP as a convenience
+for habituated FTP client users.  ckuusr.[ch], ckcftp.c, 28 Jul 2002.
+
+A while back a user asked if it was possible to MGET a bunch of files from
+an FTP server and have them all appended to each other upon arrival.  The
+obvious way to do this would have been:
+
+  mget /collision:append /as-name:bigfile *.*
+
+But to make this work, I had to get rid of the "as-name must contain
+variables" check in the MGET parser.  doftpget(): ckcftp.c, 28 Jul 2002.  
+
+Verified that it was possible to do the same thing (GET a bunch of files
+and append them all into one result file) with Kermit protocol.  It works
+fine but in this case there is no /COLLISION switch; you have to SET FILE
+COLLISION APPEND first.  30 Jul 2002.
+
+Changed COPY /APPEND to allow wild source to single destination file, e.g.
+"copy /append *.* bigfile".  ckuus6.c, 30 Jul 2002.
+
+From Mark Berryman: a replacement for zchkpath(), the VMS routine that checks
+whether a file is in the current directory; the old one (that I wrote) was
+a hack that only worked sometimes.  Martin Vorlaender verified Mark's code in
+the situation where mine was breaking (server running in captive account).
+ckvfio.c, 30 Jul 2002.
+
+PeterE reported a problem with SWITCH case labels that start with '#':
+The problem is that the SWITCH variable contents in this case happens to be
+a comment, e.g.:
+
+  CMD(M)[_forward # Stand: 24.07.2002<CR>]
+
+so the GOTO target is null.  The solution would be for SWITCH to put the GOTO
+(_FORWARD) target in quotes.  But GOTO does not strip quotes or braces from
+around its target.  Fixed in ckuusr.c, 30 Jul 2002.
+
+Fixed the SWITCH macro definition to put the _FORWARD target in quotes.
+ckuus5.c, 30 Jul 2002.
+
+PeterE also reported that an empty SWITCH case label did not work.  There's no
+particular reason why it should, but after a brief look, it wasn't that hard
+so I did it.  It required commenting out the check for empty labels and fixing
+the comparison in dogoto().  Now it's possible to read lines from a file and
+use each line as a SWITCH variable, with patterns as case labels, including an
+empty label to match empty lines, #* labels to match comment lines, etc.
+ckuus[r6].c, 30 Jul 2002.
+
+PeterE also reported the value of \%* acquiring a trailing blank when
+referenced inside a SWITCH statment.  This happens because \%* is formed using
+\fjoin() on the \&_[] array based on its dimension, and at some point the
+dimension is spuriously increased by one.  As a workaround, I made \fjoin()
+ignore trailing empty \&_[] array elements and oddly enough this also fixed
+the growing dimensions problem.  The many script torture tests reveal no ill
+effects, so it seems like a keeper.  ckuus4.c, 30 Jul 2002.
+
+Some of Peter's sample scripts made C-Kermit 8.0.201 dump core, but no more.
+
+Fixed "delete xxx" to print an error message and fail if if xxx does not exist.
+Ditto for when xxx is a directory.  ckuus6.c, 30 Jul 2002.
+
+Patches to SSL modules from Jeff based on yesterday's advisory.  ck_ssl.[ch],
+31 Jul 2002.
+
+Fixed some typos affecting the filename collision action during command-line
+FTP [M]GET.  ckcftp.c, 31 Jul 2002.
+
+Fixed SHOW FTP to handle FTP COLLISION DATES-DIFFER.  ckcftp.c, 31 Jul 2002.
+
+A while back someone pointed out that SET CONTROL UNPREFIX ALL and SET
+PREFIXING NONE gave different results.  Fixed them to use the same code.
+Also made "set prefixing none" visible.  ckuus3.c, 4 Aug 2002.
+
+Added SET CD HOME <path>, to let the user specify which directory is intended
+when "CD" or "KCD" is given by itself.  This is because in Windows, some
+applications set up their own HOME environment variable that isn't necessarily
+where the user wants "cd" to go, but redefining HOME can interfere with the
+application (example: Windows EMACS).  SET CD HOME was done by adding a myhome
+variable, initially a NULL pointer, and then changing homepath() to use it if
+it is set.  zhome() is not affected.  Also the homepath() prototype had been
+missing from header files.  ckcmai.c, ckuusr.h, ckuus[2345].c, 4 Aug 2002.
+
+PeterE got another core dump with his SWITCH statement.  Found a place where
+an out-of-bounds array reference could occur if the switch variable was
+empty.  ckuus6.c, 5 Aug 2002.
+
+PeterE noticed that if the switch variable contained a comma, spurious matches
+could occur with the label pattern.  The real problem turns out to be what
+happens when the SWITCH variable doesn't match any of the case labels and
+there is no DEFAULT label.  Fixed by having dogoto() in the SWITCH (_FORWARD)
+case pop the command stack before returning failure, i.e. by moving the
+"if (stopflg) return(0);" statement down a few lines.  ckuus6.c, 5 Aug 2002.
+
+PeterE noticed that a SWITCH case label of :* did not match an empty SWITCH
+variable.  Fixed in doswitch(): ckuus6.c, 6 Aug 2002.
+
+In testing the previous fix, I found it only worked sometimes.  Inspection
+of the debug log showed that a statement like:
+
+  if (y == -3) s = "{}";
+
+was assigning "{" rather than "{}" to s.  Replacing the string constant by a
+buffer containing the same string fixed it.  The reason (guessed correctly by
+PeterE) was the following sequence:
+
+  y = cmfld("Variable name","",&s,xxstring);
+  if (y == -3) s = "{}";
+  len = ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
+
+brstrip() (by design and as documented) affects the string in place.  But in
+this case the string is a constant, not data in a buffer, so all further uses
+of "{}" get the wrong string (at least in optimized builds).  The only real
+cure is to change brstrip() to make a copy of its argument if it has to do
+anything to it.  This will slow down some scripts, but it's too risky to
+leave it as it was.  ckclib.c, 6 Aug 2002.
+
+The previous change required an audit of the C-Kermit code to make sure that
+no references to brstrip() depended the result buffer being persistent, or the
+result pointer indicating a position in the source buffer.  Oops, it turns out
+that thousands of places rely on brstrip() working in place.  Therefore the
+change had to be undone.  There's no good way to write a dummy-proof brstrip();
+programmers either have be sure they're not calling it with a pointer to a
+string constant, or else they have to copy the result back to the right place
+each time.  Better to leave it as it was and audit the code to fix any calls
+that refer to string constants (turns out there were only two).  Restored the
+original fix to doswitch() (replacing the string constant by a buffer holding
+the same string), plus minor fixes to ckcftp.c, ckuus[r36].c, 6 Aug 2002.
+
+We need file dialogs in several situations in the K95 GUI.  I added a "user
+query" routine for this, uq_file(), in ckuus3.c, filling it in only for Unix.
+Then I added code to call it from rcvfil() when (a) it's an autodownload, and
+(b) SET TERM AUTODOWNLOAD is ASK (I just added this option; it needs to be set
+to see it in action -- maybe it should be the default for KUI, in which case
+initialize "int autodl = ?" to TAD_ASK in ckcmai.c).  Works fine, except of
+course it interferes with the file-transfer display, but that won't be a
+problem in K95G.  ckuusr.h, ckuus[37].c, ckcfns.c, ckucns.c, 6 Aug 2002.
+
+Another place we need a file dialog is when Kermit is a URL interpreter.  The
+problem is: how can we let the user decide whether Kermit should ask?  There
+really isn't any way.  Either it always asks or it never does.  In this case I
+think it makes sense to always ask if it's KUI, otherwise never.  I added the
+code for ftp: URLs to to doftprecv2(), which I tested successfully in Unix
+before putting it into #ifdef KUI..#endif.  Also added code for http[s] to
+ckuusy.c in #ifdef KUI..#endif, not tested.
+
+Still need this added for K95G Actions->Capture.  The clearest example is the
+FTP one.  Just search for KUI in the FTP module.
+
+Some minor adjustments to yesterday's work, mainly just comments, plus
+generate the full pathname for the default file.  ckuus3.c, ckcftp.c,
+7 Aug 2002.
+
+Note: for some reason cmofi() is not supplying the default value if user
+enters an empty name... (but that won't affect the Windows version).
+
+Added /USER: and /PASSWORD: switches to SET TCP { HTTP-PROXY, SOCKS-SERVER }.
+ckuus3.c, 7 Aug 2002.
+
+New 'uninstall' target from PeterE, works by having the 'install' target
+write an UNINSTALL shell script.  makefile, 8 Aug 2002.
+
+Added some debugging statements to the VMS communications i/o module to try
+to track down a problem that occurs when the controlling terminal is a LAT
+device.  ckvtio.c, 10 Aug 2002.
+
+Fixed the non-K95 uq_file() to respect the given default name, but still show
+the fully qualified absolute pathname for the default in the dialog.  The
+reason to not use the fully qualifed name as the default in the cmxxx() calls
+is that this can easily result in a whole directory tree being created due to
+directory aliases, symlinks, etc.  So when you get a file by referring to its
+URL (e.g. ftp://kermit.columbia.edu/kermit/READ.ME), uq_file() converts the
+READ.ME part to (e.g.) /home/fdc/tmp/READ.ME but gives just "READ.ME" as the
+default when parsing the name.  This way the user knows where it will go and
+gets an opportunity to change it, and if the default is accepted, it goes into
+the current directory.  uq_file(): ckuus3.c, 10 Aug 2002.
+
+Found the spot for calling uq_file() for kermit:// URL downloads.  Added
+prefatory text to filename prompts for Kermit and FTP downloads.  ckcfns.c,
+ckcftp.c, 10 Aug 2002.
+
+Now with kermit:// or ftp:// URL downloads there's no way to disable the
+prompting.  I could easily make SET TERMINAL AUTODOWNLOAD ASK cover these
+cases too (even though "terminal" has nothing to do with FTP or URL
+downloads).  OK, I did this, but now prompting is disabled by default.
+ckcftp.c, ckcfns.c.  10 Aug 2002.
+
+Enabled file prompting (adl_ask) by default in K95G, disabled it by default
+everywhere else.  So now FTP and Kermit URL downloads as well as terminal-mode
+Kermit (but not Zmodem) downloads are prompted for if TERMINAL AUTODOWNLOAD is
+ASK, which is it by default only in K95G.  But this will happen only if
+uq_file() is filled in for K95G; otherwise everything should work as before.
+ckcmai.c, 10 Aug 2002.
+
+Notes:
+ . Need a better command to control this.
+ . FTP URL downloads are almost instantaneous, whereas Kermit URL downloads
+   take a really long time to set up (logging in takes at least 10 seconds).
+
+From Jeff, 13 Aug 2002:
+ . Increase K95 version to 2.1.0: ckcmai.c.
+ . SET TCP { HTTP-PROXY, SOCKS-SERVER } /USER: /PASSWORD: actions: ckuus3.c.
+
+From PeterE: a new install target that's only about half as a big as the
+previous one, yet still generates an UNINSTALL script.  makefile, 13 Aug 2002.
+
+Vace wanted to be able to give the FTP client an offset for the server time,
+in case the server's time (or timezone) is set incorrectly.  I added this by
+building on all the date/time parsing/arithmetic code -- notably delta times
+-- that was done for C-Kermit 8.0.  The new command is SET FTP
+SERVER-TIME-OFFSET delta-time; shows up in SHOW FTP and HELP SET FTP.
+ckcftp.c, 13 Aug 2002.
+
+Fixed HELP ASK and HELP GETOK text.  ckuus2.c, 14 Aug 2002.
+
+Fixed GETOK to accept /GUI switch even in K95.EXE and C-Kermit, just like ASK
+does (in which case, it just ignores it).  ckuus6.c, 14 Aug 2002.
+
+SET XFER CHAR TRANSPARENT no longer disables character-set translation because
+file-scanning turns it back on.  The "new way" to disable character-set
+translation is SET XFER TRANSLATION OFF.  This needlessly confuses users who
+expect the old way to still work.  So I fixed SET XFER CHAR TRANSPARENT to set
+XFER TRANSLATION OFF, and SET XFER CHAR anything-else to set it back ON.
+ckuus3.c, 15 Aug 2002.
+
+Fixed SET TERM AUTODOWNLOAD { ON, OFF } to turn off the ASK flag (adl_ask).
+ckuus7.c, 16 Aug 2002.
+
+Added FEAT query to FTP client from draft-ietf-ftpext-mlst-13.txt.  FEAT is
+sent along with REST 0, MODE S, and STRU F if /NOINIT is not included in the
+FTP OPEN command.  Parsing the FEAT result is handled by turning the "auth"
+argument to getreply() into a function code: GRF_AUTH to parse AUTH reply;
+GRF_FEAT to parse FEAT reply.  For GRF_FEAT, getreply() fills in a flag array,
+sfttab[] (server feature table); sfttab[0] > 0 means server responded to the
+FEAT query, in which case individual elements are set > 0 for each supported
+feature.  ckcftp.c, 18 Aug 2002.
+
+If server sends a feature list, display it if FTP DEBUG is on, then set mdtmok
+and sizeok (the flags that say whether it's OK to send MDTM and SIZE commands)
+accordingly.  If user gives an [M]PUT /RECOVER command and server has
+announced it doesn't support REST, print a warning but try anyway (maybe
+change this later).  Responses about other features that we use such as AUTH
+and PBSZ are ignored for now -- i.e. we try them anyway.  And of course
+responses for features we don't care about (LANG, TVFS, PROT) are ignored.
+ckcftp.c, 18 Aug 2002.
+
+If the server says it supports MLST, use MLSD instead of NLST to get the file
+list.  This is done in remote_files() with some simple string-twiddling.  Then
+replace the relevant (but not all) SIZE commands with code to first check if
+we already got the size from the MLSD response and use that instead rather
+than asking again.  Same deal for MDTM.  ckcftp.c, 18 Aug 2002.
+
+Checked that this works when giving pathnames in the MGET filespec.  Checked
+to make sure everything works as before with servers that don't support FEAT
+or MLSD.  Checked to make sure FTP OPEN blah /NOINIT worked with servers that
+do support FEAT and MLSD.  Checked that FTP CHECK works.  It's all OK.
+
+Tested only with Ipswitch server; need to find and test with others.
+
+The stack of temp files needed for MGET /RECURSIVE is annoying because what
+if we run out of file descriptors...  But the spec doesn't provide a way to
+request a recursive listing.
+
+Supplied a missing comma in HELP SET CD text.  ckuus2.c, 19 Aug 2002.
+
+Generalized parsing of MLST/MLSD file facts and values.  Got file type from
+server and had MGET skip non-regular files.  ckcftp.c, 19 Aug 2002.
+
+Kirk Turner-Rustin <ktrustin@owu.edu> reported that if Unix C-Kermit has a SET
+HOST PTY connection (e.g. SSH) open, local window size changes are not
+propogated through the connection to the host.  I imagine that must be because
+the SIGWINCH signal is caught by Kermit and its children don't see it; maybe
+if I pass it along to the child fork, all will be OK.  Began by exporting
+"slavepid" from the pty module and changing its name to pty_fork_pid.  Moved
+the SIGWINCH handler, winchh(), from ckctel.c to ckutio.c.  Armed it from Unix
+sysinit() so it's always armed.  This way window changes affect Unix C-Kermit
+no matter what mode it's in: tt_rows, tt_cols, cmd_rows, and cmd_cols are all
+kept in sync.  Then if we're not in remote mode (i.e. we have a ttyfd), we
+call tn_snaws() and rlog_snaws() (which should be ok since they return right
+away if the appropriate kind of connection is not open) and then if
+(pty_fork_pid > -1), a SIGWINCH signal is sent to it.  ckupty.c, ckctel.c,
+ckutio.c, 20 Aug 2002.
+
+All this works fine except the PTY part; in other words, the original problem
+is not fixed.  The "kill(pty_fork_pid,SIGWINCH)" call executes without error
+but has no effect because the size of the PTY never changed.  To make this
+work I had to add an ioctl() to change the size of the PTY before sending it
+the SIGWINCH.  Compiles and works ok on Linux and Solaris; Kirk also confirmed
+it for AIX 4.3.3.  ckutio.c, 20 Aug 2002.
+
+Fixed xlookup() to work for uppercase keywords.  ckucmd.c, 20 Aug 2002.
+
+Fixed FTP parsefeat() and parsefacts() to use xlookup() instead of lookup(),
+since abbreviated keywords are not allowed.  ckcftp.c, 20 Aug 2002.
+
+Adjusted some lines from yesterday's window-size code for platforms I hadn't
+tried yet.  ckutio.c, 21 Aug 2002.
+
+EXIT from K95 when it has an FTP connection open and it pops up the
+Locus dialog.  Made it not do this if it knows it's in the act of EXITing.
+ckuus[rx].c, 22 Aug 2002.
+
+In K95, FTP GET in ASCII mode results in a file with Unix line terminators
+even though the protocol is correct:
+
+  RETR smjulie.txt
+  150 Opening ASCII mode data connection for smjulie.txt (1878 bytes).
+
+The source file is a regular Unix text file with LF at the end of each line.
+It's incredible that nobody noticed this before.  It only came to light when
+somebody tried to open a downloaded text file with Notepad, which doesn't
+handle Unix-format files (Wordpad and Emacs have no problems with them).  The
+problem was in doftprecv2() in the FTT_ASC section.  There was no conditional
+code for Unix vs Windows.  In all cases, the code discarded incoming CR's in
+ASCII mode.  I put the CR-discarding code in #ifdef UNIX..#endif.  ckcftp.c,
+22 Aug 2002.
+
+Removed super-verbose debugging from gtword(): ckucmd.c, 23 Aug 2002.
+
+Gregory Bond reported a problem with "if defined \$(BLAH) ..." inside of a
+SWITCH statement.  It wasn't really the SWITCH that was doing it, it was the
+fact that he had enclosed the SWITCH case in braces, which made it an
+"immediate macro" (XXMACRO).  The XXMACRO code parsed the macro definition
+(the part inside the braces) with cmtxt(...,xxstring), which should have been
+cmtxt(...,NULL) to defer the evaluation of the interior of the macro until it
+was executed.  This is better illustrated with the following example:
+
+  { echo START, for \%i 1 3 1 { echo \%i }, echo STOP }
+
+which totally fell on its face prior to the fix.  Also fixed ?-help for
+immediate macros, which was broken too.  ckuusr.c, 23 Aug 2002.
+
+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 (because RFC 959 and 1123 are
+contradictory, plus no servers follow either one of them for this anyway).  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 (which happens
+with ProFTPD).  ckcftp.c, 25 Aug 2002.
+
+Added SET FTP ANONYMOUS-PASSWORD (plus help text and show value).  ckcftp.c,
+25 Aug 2002.
+
+Made FTP command "not available" if NOFTP is defined.  ckuusr.c, 25 Aug 2002.
+
+Forced client to send a TYPE command upon initial connection, since given
+the variable quality of FTP servers, it's not safe to assume the server is
+in ASCII or any other particular mode.  ckcftp.c, 25 Aug 2002.
+
+SET FTP CHARACTER-SET-TRANSLATION ON is completely broken in K95, although it
+works fine in C-Kermit.  Furthermore it is broken in both the GUI and Console
+versions, so it's not a Unicode vs OEM console-character-set issue.
+
+Added Concurrent PowerMAX OS target from Tom Horsley.  makefile, ckuver.h,
+27 Aug 2002.
+
+Minor fixes to FTP module from Jeff.  ckcftp.c, 27 Aug 2002.
+
+New Makefile target for Mac OS X 10.2, needs -DNDSYSERRLIST added, from
+William Bader.  2 Sep 2002.
+
+SET OPT DIR /DOTFILES didn't work for server listings.  A few years ago when
+I front-ended zxpand() with nzxpand(), I missed a couple places where
+traverse() needed to refer to xmatchdot (nzxpand's argument flag) rather than
+global matchdot.  Fixed in traverse(): ckufio.c, 2 Sep 2002.
+
+From Jeff, 4 Sep 2002:
+ . setautodl(x) -> setautodl(x,y): ckuusr.h, ckuus[7y].c
+ . Add another parameter to popup_readblah(): ckuus6.c
+ . Sort out some confusion in scanfile() where a parameter was also used as a
+   local flag.  ckuusx.c.
+ . Protect restoring of saved terminal idle parameters with a flag that says
+   they were actually saved.  ckuusr.c.
+ . Rework uq_text() and uq_mtxt().  ckuus3.c.
+ . Fix FTP charset translation for little-endian hardware: ckcftp.c.
+
+The latter still doesn't work in Linux:
+
+  (/home/fdc/kermit/) C-Kermit>set ftp server-character-set latin1-iso
+  (/home/fdc/kermit/) C-Kermit>set file character-set utf8
+  (/home/fdc/kermit/) C-Kermit>get latin1.txt
+
+Results in "????????: file not found".  But it works fine on the Sun.
+
+Jeff's patch removed a little-endian byte-swap (LEBS) from doftpsend2().  But
+the real problem was that LEBS was not being done consistently throughout the
+module.  There were similar xgnbyte()/xpnbyte() loops elsewhere in the code,
+and all of them needed to work the same way.  Undoing Jeff's fix and then
+adding the LEBS to the loop in getreply() makes downloads work right, but the
+messages are still messed up (they come out in Chinese :-)  Begin by moving all
+byte-swapping operations that occur in ckcftp.c itself into a new function,
+bytswap().  It's either right to do it all the time, or to do it never; this
+way we can turn it on and off in one place.
+
+xp/gnbyte() include behavior that depends on what Kermit is doing: W_SEND,
+etc.  xpnbyte() tests W_KERMIT, which is a combination of W_SEND, W_RECV, etc.
+Defined a new symbol W_XFER, which is like W_KERMIT but includes W_FTP.  These
+are all the "whats" in which character sets might need to be converted.
+Changed the W_KERMIT reference in xpnbyte() to W_XFER.  Fixed the inderminate
+"what" state after an FTP command by moving "what = W_COMMAND;" from before
+the main parse loop to inside it (this didn't matter before the addition of
+FTP but now it does).  ckcker.h, ckcftp.c, ckuus5.c, 6 Sep 2002.
+
+Finally I changed xlatec() to be consistent with all the other xgnbyte() /
+xpnbyte() usage throughout the FTP module and, poof, everything worked in
+Linux (and still works on the Sun).  We still need some work in Windows (where
+the file character-set is not necessarily the console character set for
+messages) but we can tackle that next.  ckcftp.c, 6 Sep 2002.
+
+Checking yesterday's work:
+
+Kermit file transfers with charset translation work fine in both directions.
+
+FTP GET with charset translation works fine on both BE and LE
+
+Fixed a typo in yesterday's changes that made FTP PUT with charset translation
+always upload 0-length files.  ckcftp.c, 7 Sep 2002.
+
+FTP PUT (after the typo was fixed) with charset translation works fine on BE,
+but on LE the message comes out in Chinese and the resulting file gets ? or
+nothing for all for the accented letters:
+
+      FTP...  Kermit 
+      Up  Dn  Up  Dn  Term
+  BE  OK  OK  OK  OK   xx
+  LE  no  OK  OK  OK   xx
+
+xx = C-Kermit CONNECT mode with translation doesn't seem to do anything, not
+only in today's code, but also in the 8.0 release version: "set term char
+latin1 utf8" -- SHOW CHAR shows the right stuff, but no translation is done.
+Ditto for the 7.0 release.  That can't be right...
+
+But one problem at a time -- what's wrong with LE FTP uploads?  Note that
+XLATE works on the same machine, so it's obviously confusion in xgnbyte()
+about "what".  Suppose we make xgnbyte() ALWAYS return bytes in BE order.
+This makes sense because xgnbyte() is almost always used to feed xpnbyte(),
+and xpnbyte() requires its bytes to come in BE order.  This means that all
+code that uses xgnbyte()/xpnbyte() loops can be simplifed, which I did for
+the FTP module.  ckcfns.c, ckcftp.c, 7 Sep 2002.
+
+Of course Kermit protocol uses xgnbyte() too, but only for filling
+packets, and packets never contain UCS2 and even if they did, it would have
+to be big-endian, so no changes needed for getpkt().  Now we have:
+
+      FTP...  Kermit 
+      Up  Dn  Up  Dn
+  BE  OK  OK  OK  OK
+  LE  OK  OK  OK  OK
+
+Now let's look at the remaining xgnbyte() calls in the rest of the code:
+
+ckuus4.c:
+  xlate() uses it of course.  I simplified the general-case loop.
+  Works OK on both Sun and Linux.
+
+ckuus6.c:
+  typegetline() uses it.  I commented out the byte swap.  Seems OK.
+
+Built and tested on Linux, Solaris, and SunOS.  I'm sure I must have broken
+something, but the main things are better than they were.  Kermit and FTP
+transfers need testing in K95, as well as the TYPE command (there's a bunch of
+special K95 code in there).  C-Kermit charset translation during CONNECT is
+still broken, or else I forgot how to use it, but that's a separate issue
+since xgnbyte()/xpnbyte() are not involved.  And we still need to do something
+in FTP getreply() for K95 to convert messages to the console character set for
+display, rather than the file character set (should be trivial).  Also there's
+still a lot of extra debugging and commented-out junk in ckcftp.c to be
+cleaned up after more testing.
+
+During yesterday's testing, I noticed that REMOTE SET { FILE, XFER }
+CHARACTER-SET didn't work.  The server accepted these commands but they didn't
+seem to do anything.  In fact, they did work, but they were undone later by
+code in sfile() that restored the global settings in case they had been
+temporarily overridden by autoswitching or whatever.  The solution is to
+"unsave" the saved values whenever a global setting is performed explicitly.
+Tested successfully against Sun and Linux servers.  Also the server end of
+REMOTE SET needed updating for Unicode.  ckcfn[s3].c, ckuus3.c, 8 Sep 2002.
+
+Cleaned commented-out cruft and extra debugging from ckcftp.c.  8 Sep 2002.
+
+Kermit autodownload with ASK file dialog: if user supplied an absolute
+pathname, it was treated like a relative one.  Fixed the invocation of
+uq_file() in rcvfil() to temporarily override the RECEIVE PATHNAMES setting.
+ckcfns.c, 10 Sep 2002.
+
+Added SET TERMINAL ROLL KEYSTROKES { SEND, RESTORE-AND-SEND, IGNORE }, parse
+only.  Needs implementation (search for tt_rkeys and rollkeytab in ckuus7.c).
+ckuusr.h, ckuus[27].c, 10 Sep 2002.
+
+If FILE INCOMPLETE is DISCARD and a file is being received by IKSD but IKSD
+gets a Telnet LOGOUT command, the partial file is not deleted.  In fact this
+happens any time doexit() is called for any reason during file reception,
+e.g. because of SIGHUP.  Added code to doclean() to check if a download
+output file was open, and if so, to delete it after closing it if keep==0.
+ckuusx.c, 10 Sep 2002.
+
+Added a brief one-line message after remote-mode file transfer saying
+what (or how many) file(s) were transferred, where they went, and whether
+the transfer was successful -- kind of an automatic WHERE command, useful
+with autodownloads so you know what happened.  ckcpro.w, 11 Sep 2002.
+
+The Unix and VMS C-Kermit CONNECT modules have botched remote-charset to
+local-UTF8 translation ever since the Unicode was first added in v7.0.  Fixed
+in ckucns.c, ckucon.c, ckvcon.c, 11 Sep 2002.
+
+On to pattern-matching...  The matchdot business should apply only for (Unix)
+filename matching, not for general string matching.  Fixed in ckmatch():
+ckclib.c, 11 Sep 2002.
+
+A bigger problem occurs in filename matching.  Somehow the dirsep == fence
+business interferes with matching {foo,bar,baz} segments.  For example, I have
+a filename "foo" and I want to match it with the pattern "{foo,bar}".  Somehow
+the segment pattern becomes "*/foo" and doesn't match the string.  Where does
+the '/' get tacked on?  I don't even know how to explain this, but the short
+story was that ckmatch(), under certain circumstances, would back up to before
+the beginning of the filename string, which just happened to contain a "/"
+(and before that a ".") because of who was calling it.  Obviously this is not
+how to write a pattern matching function...  Ensuring that it never backs up
+beyond the beginning of a string fixed the immediate problem and does not seem
+to have broken any other matching scenarios (I have 150 of them in my test
+script).  ckclib.c, 11 Sep 2002.
+
+There's still a problem though.  Suppose the a client sends "dir {{.*,*}}" to
+a server.  This asks for a directory listing of all files that begin with
+dot as well as all files.  Still doesn't work because we don't normally show
+dot-files, but in this case it SHOULD work because ".*" was explicitly
+requested.  Staring at the ckmatch() code revealed how to fix this, and I did,
+but that was only half the problem.  The other half was that the list of
+files being fed to ckmatch() did not include the dotfiles in the first place.
+The cure here is to change nzxpand() to prescan the pattern to see if it
+includes a leading dot, and if so to set the "xmatchdot" flag itself, even
+if it wasn't set by the caller.  ckclib.c, ckufio.c, 11 Sep 2002.
+
+Now that {foo,bar,...} patterns work better, I added a quick hack to the
+DIRECTORY command to allow multiple filespecs to be given, in which case we
+combine them into a {file1,file2,...} pattern before calling nzxpand().  Works
+fine but it's a hack because you don't get file lists upon "?" in the second
+and subsequent filespec fields, but I doubt anyone will notice.  So now,
+finally, people can do "dir .* *" like they do in Unix (except with ls) to get
+a listing of all files in a directory without having to know about or use the
+/DOTFILES switch.  This was NOT done for the server end of RDIR because of
+ambiguity of spaces as separators versus filename characters.)  domydir():
+ckuus6.c, ckuus[r2].c, 11 Sep 2002.
+
+Added a CONTINUE command.  In a script, this does whatever CONTINUE did before
+(e.g. in a FOR or WHILE loop).  At the prompt, it calls popclvl(), which gives
+a more natural way to continue a script that has "shelled out" to the prompt.
+ckuusr.[ch], 11 Sep 2002.
+
+Added help text for CONTINUE.  ckuus2.c, 12 Sep 2002.
+
+From Jeff, 16 Sep 2002:
+ . SET TERM ROLL KEYSTROKES for K95: ckuusr.h, ckuus7.c
+ . Remove the doexit() call from the Telnet TELOPT_LOGOUT handler: ckctel.c
+
+Fixed an FTP debug message to be consistent with Kermit ones.
+ckcftp.c, 16 Sep 2002.
+
+Added SET/SHOW TRANSFER REPORT to turn the post-transfer report off and on.
+ckuusr.h, ckuus[234].c, 16 Sep 2002.
+
+Fixed Solaris (and maybe some other SVORPOSIX builds) to find out their full
+hostname rather than just short form (e.g. watsol.cc.columbia.edu rather than
+just watsol).  ckhost(): ckuusx.c, 16 Sep 2002.
+
+"cat somefile | kermit -Ts -" is supposed to send stdin in text mode, but
+K95's file transfer display reports BINARY.  Looked at C-Kermit code; it seems
+fine.  Looked at packet and debug logs; C-Kermit was indeed sending in text
+mode and announcing it correctly.  K95 gattr() is doing the right thing:
+
+  gattr file type[AMJ]=3
+  gattr attribute A=text=0
+  gattr sets tcharset TC_TRANSP[A]
+
+Same thing happens when C-Kermit is receiving.  Yet when I send an actual
+file, rather than stdin, it's received in text mode.  The only difference is
+that stdin does not have a Length attribute in its A-packet, so in this case
+the receiver skips any calls to screen() that show the length or percent done.
+Aha, so maybe it's just a display problem -- scrft() is not being called to
+repaint the file type if the size was not known.  Fixed in opena() by
+removing the IF clause from "if (fsize > -1L) xxscreen(SCR_FS,0,fsize,"");".
+ckcfn3.c, 18 Sep 2002.
+
+K95 user has a listfile containing some regular filenames and then some
+filenames that include paths and has all kinds of problems with MGET /LISTFILE
+(pieces of different names concatenated to each other, etc).  Setting up the
+same scenario here, I don't see the same problems but I do see "Refused: Name"
+when we go to get a path/name file.  This happens because (a) we had already
+got a top-level file with a certain name, (b) a file in a subdirectory has the
+same name, (c) we are stripping the path before calling zchki(), and (d)
+FTP COLLISION is set to DISCARD.  How do we make FTP not strip the path?
+
+This is an interesting question...  The answer depends on where the user
+wants the file to go.  Normally if you tell an FTP client to "get foo/bar",
+you want the file "bar" to be downloaded to the current directory.
+
+Anyway, it turns out the FTP module uses paths locally during MGET only if
+/RECURSIVE was specified.  So:
+
+  mget /listfile:blah /recursive
+
+should have made this work, but it didn't because in the /LISTFILE case,
+we have effectively turned an MGET into a series of GETs, where the code to
+check whether to strip the path didn't check the recursive flag because how
+could a GET (as opposed to an MGET) be recursive?  Adding this exception to
+the if-condition got us a bit farther but now when we try to open the output
+file in doftprecv2(), zopeno() fails because the name contains a dirsep.
+We have to call zmkdir() first but that wasn't happening because some other
+flag wasn't set right in this case.  Finally zmkdir was called, but with
+the wrong string.  After fixing that, it works.  Now we should be able
+to use /RECURSIVE to force the pathname to be used on the local end.
+ckcftp.c, 19 Sep 2002.
+
+Checked FTP filename conversion issues.  FTP FILENAMES AUTO is supposed to
+mean LITERAL if "wearealike" OR server is UNIX or Windows, otherwise
+CONVERTED, but there were places where this rule was not applied consistently,
+fixed now.  ckcftp.c, 21 Sep 2002.
+
+Added SET FTP DISPLAY, which is like SET TRANSFER DISPLAY but applies only to
+FTP, mainly because I tended to type it all the time.  Now if you have dual
+sessions, each session can have its own transfer display style.  ckcftp.c,
+ckuusr.h, ckuus[347].c, 21 Sep 2002.
+
+Back to FTP MLSD.  We're supposed to match the pattern locally, not rely on
+the server to filter its list according to the client's pattern.  Thus we must
+also allow an empty argument to MGET and must not send a filespec with MLSD.
+Actually this is tricky -- how is the client supposed to know whether to send
+a filespec.  For example, if the user's command is "mget foo*bar", and the
+server supports MLSD, then what should the client do?  The client does not
+know the wildcard syntax on the server, so for all the client knows, this
+might be a valid directory name, in which case it should be sent.  On the
+other hand, the user might intend it as a wildcard, in which case it should
+NOT be sent.  But the FTP client can't read the user's mind.  This is another
+serious flaw in the Elz/Hethmon draft.  Anyway, I got the local matching
+business working for MLSD as long as the user's MGET arg is really a pattern
+and not a directory name.  To be continued...  ckcftp.c, 21 Sep 2002.
+
+Added FTP { ENABLE, DISABLE } { FEAT, MLST }.  If we always send FEAT, we
+usually get a complaint.  If we send FEAT and MLST is negotiated, there is a
+good chance it is misimplemented or will have undesirable side effects, such
+as sending huge file lists.  NOTE: /NOINIT on the FTP OPEN command also
+disables both of these.  ckcftp.c, 22 Sep 2002.
+
+Fixed mkstemp() code in FTP remote_files().  mktemp() does not open the file,
+mkstemp() does open it; previously we had been opening it again and never
+closing the first instance so every MGET would create another open file
+descriptor.  ckcftp.c, 22 Sep 2002.
+
+Added debug messages for temp-file creation and lines read from the temp file.
+ckcftp.c, 22 Sep 2002.
+
+Eliminated sending of some extraneous TYPE commands, but there's still room
+for improvement.  ckcftp.c, 22 Sep 2002.
+
+Moved definition of build date to top of ckcmai.c.  22 Sep 2002.
+
+Added recursion to MGET with MLSD...  It's all done in remote_files().
+Temp-file pointers are on a stack (max size 128).  When parsing MLSD lines
+from the temp file and we see "type=dir", we create the local directory by
+calling zmkdir(), change to the remote by sending CWD, increment the depth,
+and call ourselves.  When reading from a temp file, upon EOF we close and
+dispose of the temp file, return -3 if currently at top level, otherwise we
+free the tmpfile name, decrement the depth, send CDUP to the server, "cd .."
+locally, and go back and read the next line from the previous but now current
+temp file.  Conceptually simple but needed hours of debugging -- what must
+be static, what must be on the stack...  Seems OK now but still needs some
+heavy testing.  ckcftp.c, 22 Sep 2002.
+
+Added FTP { ENABLE, DISABLE } { SIZE, MDTM } and add help text for FTP
+ENABLE and DISABLE.  ckcftp.c, 23 Sep 2002.
+
+Don't allow restart if SIZE disabled.  ckcftp.c, 23 Sep 2002.
+
+Make sure all implicit SIZE commands are surpressed if SIZE disabled.
+ckcftp.c, 23 Sep 2002.
+
+If an explicit FTP MODTIME command is sent when MDTM is DISABLED, and it
+succeeds, re-ENABLE MDTM.  Ditto for SIZE.  ckcftp.c, 23 Sep 2002.
+
+If an explicit FTP FEATURES command is sent during an FTP session, redo the
+features database from it.  ckcftp.c, 23 Sep 2002.
+
+After further discussion with Robert Elz, I realized I had to expose the
+underlying MGET mechanisms to the user; the draft isn't going to change, and
+the new spec will result in undesirable effects if the client tries to "do the
+right thing" by magic in all situations; thus the user must have some new
+controls:
+
+  MGET [ /MLST, /NLST, /MATCH:xxx ] [ filespec [ filespec [ ... ] ] ]
+
+These switches let the user force the use of MLSD or NLST when there's a
+choice, and to force local use of a pattern rather than sending it to the
+server, and even to send a directory name to the server at the same time as
+specifying a pattern for local matching, and of course by default we try to do
+the right thing in all scenarios.  Symbols only; not coded yet.  ckuusr.h,
+23 Sep 2002.
+
+Added the three new switches to MGET, plus /MLST is an invisible synonym for
+/MLSD.  If /NLST or /MLSD is given it, it forces the corresponding FTP protocol
+directive.  ckcftp.c, 25 Sep 2002.
+
+Now for the tricky part: now we have two separate concepts for what to send to
+the server: a filename or wildcard to be interpreted by the server (NLST only)
+or a directory from which to get a list of all the files (NLST or MLSD),
+possibly together with a pattern to be used by the client to match filenames
+returned by the server.  This required giving remote_files() an additional
+argument.  Now it uses "pattern" (if any) strictly for local pattern matching
+(because now it is the /MATCH: switch argument, not the MGET filespec), and
+"arg" (the MGET filespec) is what it sends to the server, maybe (see the
+comments in the code for the actual details); either or both these can be
+null.  ckcftp.c, 25 Sep 2002.
+
+Discovered that "mget foo", where foo is a directory name, never worked.
+Fixed in remote_files(): ckcftp.c, 25 Sep 2002.
+
+Going through every combination of NLST, MLSD, /MATCH:, and MGET arg and
+debugging each case until OK...  Then also with the panix.com NetBSD server
+(lukemftpd 1.0) which also supports MLSD....  11 test cases all debugged and
+tested OK.  ckcftp.c, 26 Sep 2002.
+
+Added /NODOTFILES switch to FTP MGET, to control what happens with dot-files
+if the server includes their names in the list (as lukemftpd does).  There's
+no point in adding a /DOTFILES switch because what could it possibly do?
+ckcftp.c, 26 Sep 2002.
+
+Changed a bunch of "skipthis++" to "continue" in doftpget(), to avoid
+error messages when skipping files that user said she wanted to skip.
+ckcftp.c, 26 Sep 2002.
+
+Added help text for the new MGET switches.  ckcftp.c, 26 Sep 2002.
+
+Don't switch LOCUS when making an FTP connection until logged in.
+ckcftp.c, 26 Sep 2002.
+
+Fixed LDIR to run Kermit's built-in DIRECTORY code rather than the external
+directory program.  ckuusr.c, 26 Sep 2002.
+
+Protect iswild() against NULL args.  ckufio.c, 26 Sep 2002.
+
+From Jeff: SET GUI WINDOW RUN-MODE { MAXIMIZE, MINIMIZE, RESTORE },
+plus variables for GUI Window X position, GUI Window Y position, GUI
+Window X resolution, GUI Window Y resolution, GUI Window Run mode.
+ckuusr.h, ckuus[24].c, 27 Sep 2002.
+
+From Ronan Flood: updated FreeBSD 1.0 makefile entry, plus an #ifdef to protect
+sysconf() calls.  makefile, ckutio.c, 28 Sep 2002.
+
+Change ftp_auth() to return(0) if an AUTH command gets a 500 response, so it
+doesn't keep sending other kinds of AUTH commands.  ckcftp.c, 29 Sep 2002.
+
+Changes from Jeff to yesterday's changes.  ckcftp.c, 30 Sep 2002.
+
+From Jeff: SSH command-line personality.  Uses same command line as the Telnet
+personality.  ckcker.h, ckcmai.c, ckuus[4y].c, 3 Oct 2002.
+
+From Jeff, 7 Oct 2002:
+ . SET PRINTER CHARACTER-SET.  ckuxla.c, ckuusr.h, ckuus[25].c
+ . Promotion of K95 to Beta.01.  ckcmai.c
+ . Promotion of SET GUI { MENUBAR, TOOLBAR } to visible.  ckuus3.c
+
+Changed the URL parser as follows: if the username and/or password fields are
+present but empty, as in:
+
+           ftp://@ftp.xyzcorp.com/somepath
+  or:      ftp://:@ftp.xyzcorp.com/somepath
+  but not: ftp://:ftp.xyzcorp.com/somepath
+
+the pointer for these items becomes a pointer to an empty string, rather than
+a NULL pointer.  Then when we go to open the connection, if the username
+string pointer points to an empty string, we prompt for the username (and/or
+password).  ckuusy.c 9 Oct 2002.
+
+Jason Heskett reported an interesting bug involving a core dump when an
+ON_EXIT macro is defined that executes another macro.  Sometimes.  He was able
+to send a short command file that always crashed.  Diagnosis: ON_EXIT, when it
+is called, pokes itself out of the macro table by setting its own entry in the
+macro name list to an empty string.  But this interferes with any macro
+lookups that are done while executing ON_EXIT's body and also evidently some
+code is not happy with empty macro names...  To fix: replace "on_exit" with
+"on_exxx", so the replacement keyword is (a) nonempty, and (b) doesn't wreck
+the alphabetical sorting of the table.  ckuusx.c, 9 Oct 2002.
+
+Added makefile targets for FreeBSD 4.6 and 5.0.  Built and tested on 4.6;
+don't know about 5.0.  ckuver.h, makefile, 9 Oct 2002.
+
+Added targets for AIX 5.2 and 5.3; totally untested.  ckuver.h, makefile,
+9 Oct 2002.
+
+Built current source on Unixware 7.1.3 (make uw7); it's fine.  9 Oct 2002.
+
+Promoted C-Kermit to 8.0.206 Beta.01 in hopes of a simultaneous release
+with K95 2.1.  ckcmai.c, 9 Oct 2002.
+
+From Jeff: Change KERMITFONT definitions to use the new (Unicode 3.1) code
+points for the terminal graphics characters (such as VT100 horizontal scan
+lines), rather than private-use codes.  ckcuni.c, 10 Oct 2002.
+
+Jason Heskett also complained that REMOTE CD would print the name of the new
+directory returned by the server even if he SET QUIET ON.  This is a tricky
+one.  Which server replies should the QUIET settings apply to?  If I give a
+REMOTE DIRECTORY command, it means I want to see the directory listing,
+period.  But if I give a REMOTE CD command, I get an "unsolicited" response
+message that SET QUIET ON should suppress.  Adding message suppression to 
+rcv_shortreply() is close, but not totally right; for example, it also
+suppresses the response to REMOTE PWD, which is not helpful.  The only right
+way to do this is to suppress for REMOTE CD only, which can be done only by
+setting a (new) global flag, rcdactive.  ckuus[r57].c, ckcpro.w, 10 Oct 2002.
+
+Ditto for REMOTE LOGIN response message ("Logged in").  ckuus7.c, 11 Oct 2002.
+
+From Jeff: SET GUI WINDOW FONT { NAME, SIZE }. ckuusr.h, ckuus4.c, 11 Oct 2002.
+
+Quick preliminary 8.0.206 build-all:
+
+ OK SunOS 4.1.3
+ OK Solaris 2.5.1
+ OK Solaris 9
+ OK AIX 4.3.3
+ OK HP-UX 10.20
+ OK VMS 7.1 Alpha + TCP/IP
+ OK VMS 7.1 Alpha nonet
+ OK VMS 5.5 VAX + TCP/IP
+ OK VMS 5.5 VAX nonet
+ OK Unixware 7.1.3
+ OK FreeBSD 3.1
+ OK FreeBSD 4.6
+ OK NetBSD 1.5.2 MVME (Gerry B)
+ OK Sinix 5.42
+
+Sinix build got stuck on ckuusr.c even though we're not optimizing on Sinix
+any more.  Rebooting the machine fixed it.
+
+Fixed some #ifdefs for VMS in new incomplete-file deletion code in doclean().
+ckuusx.c, 11 Oct 2002.
+
+Moved uq_blah() prototypes from ckuusr.h to ckcker.h because these routines
+are called in modules that don't (and shouldn't have to) include ckuusr.h.
+11 Oct 2002.
+
+Jeff verified secure builds on Linux and Solaris.
+
+Custom-build workout: 80 different feature-selection combinations:
+ . Fixed yesterday's change for NOSPL: ckcfns.c.
+ . Fixed conflict between NORECALL and USE_ARROWKEYS: ckucmd.c.
+ . Moved setseslog() from ckuus5.c to ckuusx.c to avoid link-time foulups.
+ . Fixed an unguarded reference to zmkdir() in ckcftp.c.
+ . Protected rmsg() by #ifndef NOXFER: ckuus7.c.
+ . Protected initxlist() by #ifndef NOXFER: ckcmai.c.
+ . Fixed unguarded references to g_url struct in xx_ftp(): ckuusy.c.
+ . Fixed unguarded references to tt_snaws() in winchh(): ckutio.c.
+
+--- 8.0.206 Beta.01 11 Oct 2002 ---
+
+From Jeff, 16 Oct 2002:
+ . Fix K95 RMDIR: ckcfn3.c.
+ . Makefile targets for Red Hat 7.2, 7.3, 8.0: ckuver.h, makefile.
+ . Added \v(log_xxx) for each kind of log for PeterE: ckuusr.h, ckuus4.c.
+ . Added SET TERM ATTRIBUTE DIM { ON, OFF }: ckuus[27].c.
+ . Change "const" to "CONST" in some PAM declarations.  ckufio.c.
+
+Added SET MATCH { DOTFILE, FIFO } { ON, OFF }.  A FIFO special file is a named
+pipe, used for interprocess communication.  It must be opened at both ends, so
+it's silly to match them by default; opening a FIFO and attempting to read
+will block forever unless somebody is writing into the other end.  Made the
+MATCH FIFO default OFF in all cases.  The dotfile default is the same as
+always (OFF for UNIX, ON elsewhere); SET MATCH DOTFILE is simply a more
+untuitive and findable command than SET WILD KERMIT /MATCH-DOT-FILES.  Note
+that SET MATCH DOTFILE undoes SET OPTIONS DIRECTORY /[NO]DOTFILES, and vice
+versa.  ckcmai.c, ckuusr.h, ckuus[23].c, ckufio.c. 17 Oct 2002.
+
+Added client and server end of REMOTE SET MATCH { DOTFILE, FIFO } { ON, OFF }.
+The new protocol codes are 330 and 331, respectively.  ckuus[367].c, ckcfns.c,
+17 Oct 2002.
+
+Adjusted the "match dot if pattern starts with dot" heuristic in nzxpand()
+to not kick in if the filespec is "./foo".  This probably needs more work.
+ckufio.c, 17 Oct 2002.
+
+Fixed typo in transcribing Jeff's ckcfn3.c code from yesterday.  18 Oct 2002.
+
+Moved some help text out of #ifdef ANYSSH that had nothing to do with SSH.
+(Idea for a new EMACS feature: M-X list-ifdef-environment.)
+ckuus2.c, 18 Oct 2002.
+
+Removed "set file { permission, protection }" keywords, which led nowhere.
+ckuus7.c, 18 Oct 2002.
+
+Added -DSV68 to all SV/68 targets.  Make ckgetfqhostname() just return its
+argument in SV/68; it dumps core otherwise.  In case this happens anywhere
+else, add -DNOCKGETFQHOST to CFLAGS.  makefile, ckcnet.c, 18 Oct 2002.
+
+For PeterE, added SET { SEND, RECEIVE } PERMISSIONS { ON, OFF } so incoming and
+outbound permission attributes can be set separately. ckuus[27].c, 18 Oct 2002.
+
+Changed SHOW ATTRIBUTES to show In and Out permissions separately.
+ckuus5.c, 18 Oct 2002.
+
+Fixed REDO to display the command it's redoing and to add it to the bottom
+of the recall buffer.  ckuusr.c, 18 Oct 2002.
+
+Discovered that DATE SATURDAY dumps core...  Apparently it always did; this
+case was not included in the date-time torture test script.  The crash happens
+because the DATE parsing code doesn't check for a NULL date-converion
+error-message pointer.  Fixed in ckuusr.c, 18 Oct 2002.
+
+The reason DATE SATURDAY got a date-conversion error was that this path thru
+the code left a result pointer unset.  Fixed in cmcvtdate(): ckucmd.c,
+19 Oct 2002.
+
+DATE SUNDAY +1DAY returned incorrect results (for any day-of-week name, any
+delta time), even though DATE TODAY +1DAY worked fine.  Fixed in cmcvtdate():
+ckucmd.c, 19 Oct 2002.
+
+SET TAKE ECHO ON counted each line twice when GOTO was active.  Fixed in
+dogoto(): ckuus6.c, 19 Oct 2002.
+
+Jeff noticed:
+"KERMIT READY TO GET...
+ RCVD: (2 files) Last: [/amd/prost/p/kd/jaltman/.src/ckonet.c] (OK)
+the last file attempted may have been ckonet.c but it certainly was
+not the last file received" (similarly for sending).  Fixed by having two
+pointers for each name; a preliminary pointer, which is set for each file at
+the beginning of the transfer (when we have all the needed info), and a final
+one that is set from the preliminary one only after the file was transferred
+successfully.  This corrects not only the automatic "wheremessage" at the end
+of a remote-mode transfer, but also the WHERE and SHOW FILE command results.
+ckuusx.c, ckcfn[s3].c, ckcpro.w, 19 Oct 2002.
+
+From Jeff: Improve ORIENTATION message for K95 to say which directories are
+for which INI files.  ckuusr.c, 23 Oct 2002.
+
+Removed Beta designation from herald.  ckcmai.c, 23 Oct 2002.
+
+Put final dates and ID strings in Unix and VMS build procedures.
+Makefile, ckvker.com, 23 Oct 2002.
+
+Build-all...  #ifdef adjustments: ckcfns.c...  83 different feature-set
+combinations build OK on Linux.  23 Oct 2002.
+
+From Jeff: SET WIN95 HORIZONTAL-SCAN-LINE-SUBSTITUTIONS.  ckuusr.h, ckuus7.c,
+24 Oct 2002.
+
+Fixed Heath-19 graphic character-set table to use new Unicode 3.1 values
+if WIN95 HORIZ OFF.  ckcuni.c, 24 Oct 2002.
+
+Changed tx_usub() to return Unicode 3.1 values if WIN95 HORIZ OFF.
+ckcuni.c, 24 Oct 2002. <-- No backed off on this.
+
+Some problems during build-all:
+
+ . VMS 7.1 TGV 4.2: If I make a Telnet connection with it, then try to send
+   a file (itself. wermit.exe) over the connection, the connection drops
+   after about 20%, the thermometer zooms out to 100% and SUCCESS is reported.
+   This doesn't happen with UCX.
+
+ . VMS 7.3 TGV 4.3: ckcmai.c won't compile because of a complaint about the
+   declaration of select() (which ckcmai.c doesn't use) in
+   SYS$COMMON:[SYSLIB]DECC$RTLDEF.TLB.  Ditto in VMS 7.2 TGV 4.3.
+   Adding NOSELECT to CFLAGS doesn't help.  I don't think the VMS version
+   even uses select().  But the TGV 4.3 builds were OK in 8.0.201, so what
+   changed?  I don't see anything in ckcnet.h that would have done it.
+
+It builds OK with VMS 7.1 / TGV 4.2 but sending files on Telnet connections
+fails in a strange way: the connection drops, but the thermomoter goes to 100%
+and success is reported.  I don't know why the connection is dropping (s_errno
+is 32 == "broken pipe"), but the spurious success indication is because of
+a double failure in sdata(): (1) The packet-sending loop index could go
+negative without breaking the loop when streaming; (2) if spack() fails,
+sdata() should return -2, not -1 (which means EOF).  Also if any ttchk() in
+sdata() returns < 0, sdata should return -2.  I fixed this code (which has
+been this way for YEARS) and now VMS C-Kermit properly fails when it gets
+the spack() error, but ttchk() in this case still doesn't think the connection
+is lost, but that must be our new problem with MultiNet.  ckcfns.c,
+27 Oct 2002.
+
+The compilation failure in ckcmai.c is a clue...  The problem was that I added
+#ifdef VMS / #include <time.h> / #endif to shut up complaints about the time()
+call.  Evidently something in VMS <time.h> gives MultiNet a bad case of
+indigestion; removing it fixes the compilation and the result works fine.  The
+transmission failures in the other case seem to be a coincidence -- something
+to do with the U of Arizona (probably some obscure VMS quota on my IDs there,
+or some kind of network connection throttling), since it doesn't happen
+anywhere else.  ckcmai.c, 27 Oct 2002.
+
+Changed four occurrences of "void" to "VOID" in ckcftp.c, 27 Oct 2002.
+
+Defined NOCKFQHOSTNAME for HPUXPRE65.  Might also need this for HP-UX 7
+and maybe 8.  ckcnet.c, 27 Oct 2002.
+
+From Jeff: PAM_CONST definition to clear up warnings caused by different
+vendors' definitions of PAM structs.  ckufio.c, 28 Oct 2002.
+
+Unixware 2.1.0 build bombs immediately with "UX:make: ERROR: line too long"
+(which line?)  Not worth chopping up the makefile to fix but in a pinch it
+could be done.  2.1.3 builds OK.
+
+Did another 20-some platform builds, bringing the total to 83, plus a final
+runthrough of the build-with-84-different-feature-set-combinations script on
+Linux.  Should be good to go!
+
+--- 8.0.206 24 Oct 2002 ---
+
+Finally got access to Linux on IA64 again.  Builds OK but dumps core
+immediately on startup.  Adding -DNOCKGETFQHOST was necessary but not
+sufficient.  In this case, the very call to ckgetfqhostname() from ckhost()
+(which is in ckuusx.c) was dumping core; thus I had to move the definition of
+NOCKGETFQHOST from ckcnet.c to ckcdeb.h, add an #ifdef __ia64__ clause to it,
+and protect the call to ckgetfqhostname() with it.  Obviously there has to be
+a better fix but this will have to for now.  ckcnet.c, ckuusx.c, ckcdeb.h,
+31 Oct 2002.
+
+Link step fails in Mandrake 9.0 with undefined references to res_search,
+dn_expand, and crypt.  Turns out the linux makefile target tests for the
+existence of libcrypt.a and libresolv.a, but in Mandrake 9.0 they exist
+only as *.so.  Changed linux target to look for both.  makefile, 1 Nov 2002.
+
+Vace reported that "ftp mget a b c" would get ALL files from the server's
+directory if c did not exist.  Diagnosis: off-by-one error in counting MGET
+args processed.  Naturally fixing this bug revealed another (this time
+cosmetic) one, which resulted in spurious error messages when hitting MGET
+args that have no match on the server.  Fixed in ckcftp.c, 1 Nov 2002.
+
+Rebuilt about 60 of the most important Unix binaries to pick up the fixes
+31 Oct - 1 Nov 2002, and refreshed the FTP site with new sources, tarballs,
+ZIP files, etc.  Sat Nov  2 19:11:30 2002
+
+From Martin Vorlaender and Jeff, SSL/TLS support for VMS:
+ckuusr.h, ckuath.h, ckcnet.c, ckctel.c, ckuath.c, 10 Nov 2002.
+
+Added PASV as invisible synonym for PASSIVE.  ckcftp.c, 10 Nov 2002.
+
+--- 8.0.206 24 Oct 2002 #2 ---
+
+More work on SSL in VMS: Jeff + Martin Vorlaender: ck_ssl.c ckcmai.c ckcnet.c
+ckctel.c ckuath.h ckvcon.c ckvtio.c ckvker.com 10-15 Nov 2002.
+
+Discovered that ckvfio.c would not compile on VMS 6.1 with UCX 4.1 because 
+<conv$routines.h> was missing, which is explicitly included.  Enclosed the
+#include in #ifdef NOCONVROUTINES..#endif and rebuilt with
+@[users.fdc.src]ckvker.com "" "" "NOCONVROUTINES".  16 Nov 2002.
+
+Fixed the "ftp mget */data/*" problem with two small changes to doftpget():
+ckcftp.c, 16 Nov 2002.  Placed a copy of ckcftp.patch in ~kermit/f.
+
+From Lucas Hart: Fixes for VAX C 2.x and CMU TCP/IP.  "Can't guarantee that
+the revised CKVOLD will work for all combinations of more recent
+VMS/compiler/TCPIP releases, but I've tested it for compatibility on our AXP
+VMS 6.2, UCX 4.0, DECC 5.6, your AXP VMS 7.1, DEC TCPIP 5.1, DECC 6.0 as well
+as with VAX VMS 5.4, VAX C 3.2, CMU12 and VAX VMS 4.7, VAX C 2.4."  ckvfio.c,
+ckvtio.c, ckuus5.c, ckvker.com, ckvold.com, 17 Nov 2002.
+
+From Jeff: More work on VMS SSL.  Now it actually works, even in CONNECT mode,
+except it hangs when it gets an error alert or the remote closes the
+connection.  ckcnet.c. ckvtio.c, 17 Nov 2002.
+
+NOTE: Lucas's changes should go into the 8.0.206 source code but it's too
+late since ckvtio.c (upon which he based his changes) is already full of
+SSL code.
+
+MGET in K95 in totally broken FOR SOME PEOPLE (mainly me) if the TMP (or TEMP)
+value is too long.  It works fine if you set these to C:\TMP.  Diagnosis: (1)
+we were malloc'ing only 16 bytes for the temp file name (I think this was my
+fault -- I was only looking at the "ckXXXXXX" part and forgetting that this
+was appended to the TMP path); (2) the Windows version of mktemp() wants you
+to use the value pointed to by the pointer it returns, rather than assuming
+the mktemp() arg will be modified in place.  The code was changed to malloc a
+longer string and to use the return value from mktemp() (if any) rather than
+assuming that mktemp() modified its argument string (in K95 only -- not sure
+about Unix platforms; the man pages differ on this, but at least this way if
+some mktemp() version does NOT alter its argument, we still have a usable
+filename (like /tmp/ckXXXXXX)).  Of course this won't be good for recursive
+MLSD downloads, but we can always issue patches for the Unix version later if
+needed.  The Linux and BSD versions use mkstemp() anyway.  There is, however,
+a danger of a memory leak in the Unix version if the user has defined a TMPDIR
+or CK_TMP environment variable whose value is longer than 9 bytes.  All this
+is highly unlikely so we should be OK.  ckcftp.c, 17 Nov 2002.
+
+--- K95 2.1.1 and updated ck[uv]206.{tar,zip} but not C-Kermit binaries ---
+
+From Jeff: Fixes for Telnet Com Port Control, update to a newer release of
+OpenSSL: ck_ssl.c ck_ssl.h ckcdeb.h ckcftp.c ckcmai.c ckcnet.c ckctel.c
+ckuath.c ckuath.h ckucns.c ckuus4.c ckuus5.c ckuusr.c ckuusr.h ckvcon.c
+ckvfio.c ckvker.com ckvtio.c ckvvms.h, 25 Nov 2002.
+
+--- K95 2.1.2 and C-Kermit 8.0 CDROM ---
+
+From Jeff, 28 Nov 2002:
+ . Updated SSL modules: ck_ssl.[ch].
+ . Fixed cipher-list display in SHOW AUTH & FTP ssl_auth(): ckuus7.c. ckcftp.c
+ . Some minor tn_wait() fixes: ckctel.c.
+ . Preliminary SSL support for VMS CONNECT: ckvcon.c.
+
+Bumped C-Kermit edit number to 207.
+
+From Jeff, 29 Nov 2002: "[C-Kermit was dumping core on SCO OSR5 Telnet Com Port
+connections because] the SCO compiler treats all characters as signed.  This
+was causing 'sprintf(buf,"02x ",ch);' to produce strings such as "ffffffc2"
+instead of "c2" for values between 128 and 255.  This wrote beyond the end of
+a buffer and blew away the stack.  Having fixed this I also noticed that
+conect() did not properly check for carrier when TN CPC was negotiated.  This
+has now been fixed as well."  ckucns.c, ckucon.c, ckctel.c, 29 Nov 2002.
+
+From Jeff, 30 Nov 2002: Fix SSL for VMS and also carry forward the CPC fixes
+to VMS.  ckcnet.c, ckvtio.c, ckvcon.c, 30 Nov 2002.
+
+Changed copyright dates that are displayed (but not yet all the internal
+ones) from 2002 to 2003.  ckcmai.c, 3 Jan 2003.
+
+Fixed the FTP module's brief-format transaction log, which had the status
+inverted: OK for FAILED and v.v.  ckcftp.c 3 Jan 2003.
+
+From Jeff, 4 Jan 2003:
+ . Make /MOVE-TO:xxx convert xxx to full pathname: ckuus[r67].c,
+ . Make SHOW OPTIONS ALL show both kinds of options: ckuus2.c.
+ . More command-line personalities: ckcmai.c, ckuusy.c.
+ . New NOSCROLL command for K95: ckuusr.[ch], ckuus2.c.
+ . New lockdown and other command-line options: ckuusr.h, ckuusy.c.
+ . SSL interface updated to OpenSSL 0.9.7: ck_ssl.c.
+ . SET TERM LINE-SPACING and CURSOR xxx NOBLINK: ckuus[27]c.
+ . Expanded SHOW GUI command: ckuus3.c
+ . New SHOW TABS code: ckuus5.c.
+
+Updated SUPPORT (BUG), NEWS, and INTRO texts.  ckuus[26].c. 5 Jan 2003.
+
+Fixed FTP module to suppress "'FEAT': Command not understood" message
+unless FTP DEBUG is ON.  ckcftp.c, 6 Jan 2003.
+
+Got a report that C-Kermit dumps core on Solaris when executing a certain
+script.  Seems to be related to changing vnambuf[] in zzstring() from an
+automatic array to a malloc'd buffer (see notes from 29 Jun 2000).  Changed
+it to an automatic buffer except for K95.  ckuus4.c, 6 Jan 2003.
+
+Nope, that's not it.  It evidently happens only after FTP PUT has been used.
+Fixed solaris9g makefile target to include -funsigned-char and built a new
+binary.  Determined that building with gcc and -funsigned-char makes no
+difference.  makefile, 7 Jan 2003.
+
+I did a preliminary audit, looking at the items in the left column: if used in
+a given routine, are there any obvious mistakes:
+
+                       1        2          3           4              5
+                   doftpput->putfile->sendrequest->doftpsend2->secure_write
+malloc                OK       OK         OK          OK             OK
+makestr               OK       OK     	  OK          OK    	     OK
+automatic arrays      OK       OK     	  OK          OK    	     OK
+[ck]str[n]cpy         OK       OK     	  OK          OK    	     OK
+[ck]str[n]cat         OK       OK     	  OK          OK    	     OK
+sprintf               OK       OK     	  OK          OK    	     OK
+nzltor                OK       OK     	  OK          OK    	     OK
+zfnqfp                OK       OK     	  OK          OK    	     OK
+memcpy                OK       OK     	  OK          OK    	     OK
+bcopy                 OK       OK     	  OK          OK    	     OK
+
+secure_write sends the data directly on clear-text connections.  On secure
+connections, it calls secure_putbuf(), which calls secure_putbyte(), but we
+aren't using those, so secure_write() is the end of the call chain for FTP
+PUT.  doftpsend2 has buf[] as an automatic array, which it reads file data
+into using zxin (binary mode only), but this looks OK.  Still, I changed it
+read 1 less than the buffer size (fread) just in case.  Also there was one
+debug() statement that referred to an automatic array (fullname[]) before it
+was initialized (but not used in this case), which I fixed.  ckcftp.c,
+7 Jan 2003.
+
+FTP GET /RECURSIVE somepath/somefile still didn't work, despite what the
+notes of 19 Sep 2001 say.  There are so many paths through the code,
+depending on switch values, GET vs MGET, etc, that a crucial spot was missed.
+Fixed in doftpget(): ckcftp.c, 7 Jan 2003.
+
+Back to the core dump...  after two days of full-time debugging, I found the
+culprit: the buffer-full test in the zzout() macro should have been ">="
+rather than just ">", thus Kermit wrote 1 byte past the end of the malloc'd
+FTP PUT output buffer, ucbuf.  Why did it never happen in K95?  Because, since
+it's a secure build, FUDGE_FACTOR is defined there.  But it's not defined in
+Solaris or other clear-text builds.  Although the crash wouldn't happen in
+secure builds, the 1-byte leak might have caused errors in the data transfer.
+In non-Solaris clear-text builds, like Linux, I suspect that malloc() tends
+add something for safety (especially given the man page statement that it
+allocates "at least" what you asked for).  Another reason the problem escaped
+notice is that zzout() is used only for text-mode PUTs (and then only when
+there is no character-set translation), but most transfers these days are
+binary and/or downloads.  Anyway, in the course of debugging, a lot of small
+cleanups were done: sizeof(blah) for all arrays was replaced by the same
+symbolic size that was used to allocate the array, numeric array sizes were
+replaced with symbolic ones, etc.  The real fix is one character long.
+ckcftp.c, 9 Jan 2003.
+
+Got a report that "mget /recursive */somedir/*" downloaded the files into
+the current directory, rather than re-creating the remote directory structure.
+Fixed in doftpget(): ckcftp.c, 10 Jan 2003.
+
+Unix C-Kermit did not allow file transfer if started under inetd and accessed
+via Internet raw socket (or whatever).  Diagnosis: isatty() and friends would
+fail causing ttopen() to fail.  Fixed by adding escape clauses for "-l 0"
+situations (i.e. Kermit invoked with an already-open file descriptor) at the
+appropriate places.  ckcmai.c, ckutio.c, 14 Jan 2003.
+
+From Jeff for K95 2.1.3
+ . Add test for startflags & 128 to trap() for ignoring BREAK.
+ . Fix for SHOW TRANSMIT.
+
+--- K95 2.1.3 ---
+
+FTP USER, FTP ACCOUNT, plus the various prompts and switches for FTP username,
+password, and account all neglected to strip quotes, and in most cases quotes
+are necessary to specify a username that contains spaces.  ckcftp.c,
+15 Jan 2003.
+
+FTP MPUT f1 f2 f3... gets a parse error if any of the fn's do not match an
+existing file.  This is bad for scripts.  In doftpput(), cmfdb() looks for
+keywords (switches) or CMIFI.  When it hits CMIFI, it exits from the initial
+parse loop and then does additional cmifi()s in a loop until done.  The most
+obvious fix is to parse each field with cmfdb(CMIFI,CMFLD), i.e. fall back to
+CMFLD if CMIFI doesn't match anything.  Then if CMFLD was used, we don't add
+the filespec to the list.  This is a rather big change but it seems to work.
+No error messages or failures happen for non-matching fields, but an error
+message is printed (and the MPUT command fails) if none of the fields match
+any files.  This fix got in too late for 2.1.3; workaround: use C-Shell
+like wildcard list (ftp mput "{*.abc,foo.*}").  ckcftp.c, 16 Jan 2003.
+
+GREP did not pass its pattern through the expander, thus variables could
+not be used for patterns.  This must have been an oversight -- I can't find
+anything in my notes about it.  Fixed in dogrep(): ckuus6.c, 24 Jan 2003.
+
+New makefile target for HP-UX 11.xx with OpenSSL from Tapani Tarvainen.
+makefile, 31 Jan 2003.
+
+From Jeff:
+ . Avoid core dump when dereferencing tnc_get_signature(): ckuus4.c.
+ . Bump version numbers to 8.0.208, 2.1.4: ckcmai.c.
+
+Added /NOLOGIN to FTP [OPEN].  ckcftp.c, 10 Feb 2003.
+
+Don't dump core if FTP DEBUG is ON and FTP OPEN does not include a service.
+openftp(): ckcftp.c, 10 Feb 2003.
+
+HELP PATTERN text incorrectly identified commands and functions with
+floating and anchored patterns.  The corrected lists are:
+Floating: GREP, TYPE /MATCH:, /EXCEPT: patterns, \farraylook(),
+Anchored: IF MATCH, file-matching wildcards, \fsearch(), \frsearch()
+ckuus2.c, 10 Feb 2003.     
+
+INPUT n \fpattern(xxx) did not work for case-independent comparisons.
+Fixed in doinput(): ckuus4.c, 10 Feb 2003.
+
+It seems \fpattern() didn't work with MINPUT at all.  There was no code to
+handle \fpattern() in the MINPUT parse loop, so it never worked.  The code
+had to be totally rewritten to use cmfld() in a loop, rather than cmtxt()
+and then cksplit().  Furthermore, whenever any of the fields was an
+\fjoin(), this had to be split.  ckuusr.c, 10 Feb 2003.
+
+Macro replacement via \m() and \fdefinition() does not work as advertised
+(i.e. case sensitively) for associative array elements; e.g. \m(xxx<abc>) is
+treated the same as \m(xxx<ABC>), contrary to section 7.10.10 of the C-Kermit
+7.0 update notes, and to the fact that the two really do exist separately.
+Fixed by adding a static function isaarray(s) which succeeds if s is an
+associative array reference and fails otherwise, and then having \m()
+and \fdef() call mxxlook() (case-sensitive lookup) if isaarray(), otherwise
+(as before) mxlook()).  ckuus4.c, 11 Feb 2003.
+
+Fixed FTP OPEN to allow the /USER switch to override SET FTP AUTOLOGIN OFF,
+just as /NOLOGIN overrides SET FTP AUTOLOGIN ON.  ckcftp.c, 11 Feb 2003.
+
+In K95, "set key \1234 \27H" (any SET KEY command in which the first char of
+the definition was backslash, and the ONLY character after the backslash
+quantity was an uppercase letter, that letter would be lowercased).  Diagnosis:
+xlookup() poking its argument (see notes from July 2000).  Jeff sent a fix.
+ckucmd.c, 15 Feb 2003.
+
+Ran my S-Expression torture test to make sure Sexps still worked.  They do,
+except the bitwise & and | operators were broken, e.g. (& 7 2) and (| 1 2 4)
+get "Invalid operand" errors.  Jeff's code had added an early failure return
+from the lookup loop when when a single-byte keyword matched a keyword that
+started with the same byte but was more than one byte long.  So "&" would hit
+"&&" and fail instead of continuing its search (xlookup tables aren't sorted
+so there can be no early return).  Fixed in xlookup(): ckucmd.c, 16 Feb 2003.
+
+Got rid of "krbmit" target from makefile.  It's still there, but we don't
+use it any more.  All secure targets now use "xermit", and produce a binary
+called wermit, just like the regular ones do (except the old ckucon.c ones).
+Non-secure targets, since they don't define any of the security symbols,
+wind up compiling and linking to (mostly) empty security modules.  makefile,
+15 Feb 2003.
+
+Added \fcvtdate(xxx,3) to format its result in MDTM format (yyyymmddhhmmss,
+all numeric, no spaces or punctuation).  Of course these numeric strings
+are too big to be 32-bit numbers and are useless for arithmetic, but they're
+useful for lexical comparison, etc.  ckuus[24].c, 16 Feb 2003.
+
+The following FTP commands did not set FAILURE when they failed: RMDIR,
+CD, CDUP, Fixed in the corresponding doftpblah() routines.  ckcftp.c,
+16 Feb 2003.
+
+RENAME would sometimes not print an error message when it failed, e.g. in K95
+when the destination file already existed.  ckuus6.c, 17 Feb 2003.
+
+Fixed COPY error messages, which did not come out in standard format when
+/LIST was not included.  ckuus6.c, 17 Feb 2003.
+
+Fixed #ifdefs in ck_crp.c to allow nonsecure builds on old platforms like
+System V/68 R3.  19 Feb 2003.
+
+Similar treatment for ck_ssl.c.  20 Feb 2003.
+
+From Jeff, 21 Feb 2003:
+ . AIX53 and AIX52 symbols for ckcdeb.h, makefile.
+ . New gcc targets for various AIX 4.x/5.x versions: makefile.
+ . Copyright date updates: ck_crp.c, ck_ssl.c.
+ . ENABLE/DISABLE QUERY broken because keyword table out of order: ckuusr.c.
+ . Fixed the use of HTTP proxies for HTTP [RE]OPEN for Unix: ckcnet.c.
+
+Also for K95 only: Allow file transfer when K95 is invoked on the remote end
+of a connection to a Pragma Systems Terminal Server connection; automatically
+SET EXIT HANGUP OFF when invoked with open port handle ("k95 -l nnnn").
+
+"cd a*" failed even when "a*" matched only one directory.  Fixed in cmifi():
+ckucmd.c, 21 Feb 2003.
+
+In the Unix version, replace "extern int errno;" with "#include <errno.h>"
+if __GLIBC__ is defined, since glibc now defines a thread-specific errno.
+ckcdeb.h, 26 Feb 2003.
+
+Added #ifdefs to skip compilation of ckuath.c in nonsecure builds.  Tested
+by building both secure and regular versions in Linux.  ckuath.c, 26 Feb 2003.
+
+Ran the build-in-84-different-configurations script on Linux to make sure it
+still builds with all different combinations of feature selection options.
+All OK.  26 Feb 2003.
+
+Built on VMS.  Needed to add a prototype for mxxlook*() to ckuusr.h; built
+OK otherwise.  26 Feb 2003.
+
+From Jeff: More #ifdef shuffling for nonsecure builds: ckuath.c, ck_ssl.c,
+27 Feb 2003.
+
+Added code to ensure \v(download) ends in a directory separator in Unix,
+Windows, and OS/2.  ckuus7.c, 27 Feb 2003.
+
+Added code to K95 zfnqfp() to tack on directory separator when returning
+a directory name.  ckofio.c, 27 Feb 2003.
+
+Somehow an old copy of ckuath.c popped to replace the new one.  Put the new
+one back.  28 Feb 2003.
+
+From Jeff: Fix typo in my K95 zfnqfp() code from yesterday; fixes for handling
+UNCs uniformly, no matter which way their slashes are leaning.  ckofio.c,
+28 Feb 2003.
+
+At Jeff Mezei's suggestion, separate text and binary mode open sequences
+for VMS session log.  ckvfio.c, 28 Feb 2003.
+
+Added freebsd48 target for FreeBSD 4.8.  makefile, 1 Mar 2003.
+
+Changed Mac OS X entries to include -DUSE_STRERROR.  makefile, 2 Mar 2003.
+
+Fixed GETOK /GUI to evaluate its text argument.  ckuus6.c, 3 Mar 2003.
+
+Jeff fixed the K95 Dialer QUICK dialog to (a) allow templates, and (b) have
+a Save-As option.  3 Mar 2003.
+
+Jeff fixed a problem with the Xmodem-CRC checksum being crunched whenever
+there was a retransmission.  7 Mar 2003.
+
+Added target/banner for Tru64 5.1B.  makefile, ckuver.h, 5 Mar 2003.
+
+In Unix, the zcopy() routine (used by the COPY command) reset the user's umask
+to 0 for the remainder of the Kermit process lifetime.  The bug was in
+ckufio.c 8.0.194, 24 Oct 2002, and is fixed in ckufio.c 8.0.195, 6 Mar 2003.
+Of course this happened after building 155 C-Kermit 8.0.208 binaries.  (But
+before officially releasing 8.0.208.)
+
+In the VMS version, changed:
+
+        while ((n--) && xx_inc(2) > -1) ;
+to:
+        while ((n--) && xx_inc(2) >= 0) ;
+
+to suppress the "...is being compared with a relational operator to a constant
+whose value is not greater than zero" warning.  ckvtio.c, 7 Mar 2002.
+
+Added a debug call to dologend in hopes of catching overzealous Locus
+switching, which seems to happen only in K95.  ckuus3.c, 7 Mar 2002.
+
+Rebuilt binaries for some of the more current Unix releases: AIX 4.3.3-5.1,
+Solaris 7-9 , Red Hat 7.0-8.0, Slackware 8.1, Freebsd 4.7-4.8, NetBSD 1.6,
+OpenBSD 3.2, Unixware 7.1.3, Open Unix 8, OSR5.0.6a, etc.  A Unix binary with
+COPY umask fix shows a 6 Mar 2003 date for "UNIX File support" in SHOW
+VERSIONS; a binary without the fix shows 24 Oct 2002.
+
+C-Kermit 8.0.208 dated 14 March 2003 released on 10 March 2003.
+
+---8.0.208---
+
+From Jeff 13 Mar 2003:
+ . Updated SSL module allows importation of tickets from host.
+ . freebsd50+openssl target: makefile.
+ . FTP PUT /PERMISSIONS error message for K95: ckcftp.c.
+ 
+Fixed MINPUT to strip quotes or braces from around targets (this was broken
+on Feb 10th).  Thanks to Jason Heskett for discovering and reporting this
+(killer) bug.  ckuusr.c, 14 Mar 2003.
+
+Changed version number to 209 Dev.00.  ckcmai.c, 14 Mar 2003.
+
+While debugging the alphapage script, I found that the command "minput 8 \6\13
+\21\13 \13\27\4\13 \30\13" gets "?Not confirmed" in 8.0.208 and 8.0.209, but
+not in 206 and earlier.  This problem too was introduced on Feb 10th by
+changing MINPUT parsing from cmtxt() followed by cksplit() to cmfld() in a
+loop.  cmfld() uses setatm() to return its result and of course setatm()
+breaks on \13.  Changing setatm() not to do this would break everything else.
+But cmfld() has no arguments that let us tell it to do anything different in
+this case.  Changing the API would be a disaster.  The only solution is to add
+an "MINPUT ACTIVE" (minputactive) global variable that tells cmfld() to tell
+setatm() not to break on CR.  Now MINPUT with braced targets containing CR
+and/or LF works in 209, 206, and 201 (but not 208).  ckucmd.c, ckuusr.c,
+ckuus5.c, 15 Mar 2003.
+
+MINPUT n \fjoin(&a) works OK if all the members of \&a[] are text strings, but
+if they are strings of control chars (as above), they don't get separated by
+the spaces.  For example in:
+
+  dcl \&a[] = "\4\5" "\6\7" xxx
+  minput 10 \fjoin(&a)
+
+MINPUT gets two targets: "aaa" and "\4\5 \6\7 xxx".  The bug was in the
+cksplit() call in the \fjoin() case of MINPUT: it needed to specify an
+include set consisting of all the control characters except NUL.  ckuusr.c,
+16 Mar 2003.
+
+But there's still a problem:
+
+  dcl \&a[] = "\4\5\13\10" "\6\7" "xxx"
+
+creates an array whose first member is "^D^E (one doublequote included).  But
+if braces are used instead, there's no problem.  Same deal as MINPUT: cmfld()
+breaks on CR or LF, thus the end quote is lost.  If I set minputactive for
+DECLARE initializers too, that fixes it.  Is there any reason not to do this?
+Can't think of any (famous last words)...  ckuusr.c, 16 Mar 2003.
+
+Since it has multiple applications, changed the flag's name from minputactive
+to keepallchars.  ckucmd.c, ckuus[r5].c, 16 Mar 2003.
+
+\v(exedir) wasn't being set correctly (it included the program name as well
+as the directory).  Fixed in getexedir(): ckuus4.c, 16 Mar 2003.
+
+SET CARRIER-WATCH <Esc> "auto matic" (spurious space in supplied keyword).
+Cosmetic only; it still worked.  Fixed in setdcd(): ckuus3.c, 16 Mar 2003.
+
+"directory a b c" listed too many files -- all files whose names END WITH a,
+b, or c, rather than the files whose names WERE a, b, or c.  Diagnosis: The
+filespec is changed into a pattern: {a,b,c}, which is the correct form.  It is
+passed to nzxpand(), which goes through the directory getting filenames and
+sending each one to ckmatch() with the given pattern.  ckmatch() receives the
+correct pattern but then prepends a "*" -- that's not right.  It's not just
+in filename matching either.  The following succeeds when it shouldn't:
+
+  if match xxxxc {{a,b,c}} <command>
+
+Changing ckmatch() to not prepend the "*" to each segment fixes the command
+above but breaks lots of others.  Running through the "match" torture-test
+script shows the problem occurs only when the {a,b,c} list is the entire
+pattern, and not embedded within a larger pattern.  Testing for this case
+fixed the problem.  ckmatch(): ckclib.c, 16 Mar 2003.
+
+Fixed FTP MODTIME to not print anything if QUIET ON.  ckcftp.c, 16 Mar 2003.
+
+Picked up a new ckuath.c from Jeff, not sure what the changes are. 16 Mar 2003.
+
+Did a few regular and secure builds to make sure I didn't wreck anything.
+
+Changed version number to 209 (final).  ckcmai.c, 16 Mar 2003.
+
+Jason Heskett found another bug: if you define a macro FOO inside the
+definition of another macro BAR, and FOO's definition includes an odd number
+of doublequotes (such as 1), FOO's definition absorbs the rest of BAR's
+definition.  Example:
+
+  def TEST {
+    .foo = {X"}
+    sho mac foo
+  }
+  do test
+  sho mac foo
+
+Results in:
+
+  foo = {X"}, sho mac foo
+
+Diagnosis: the TEST definition becomes:
+
+  def TEST .foo = {X"}, sho mac foo
+
+and the macro reader is erroneously treating the doublequote as an open
+quote, and then automatically closes the quote at the end of the definition.
+The error is that a doublequote should be significant only at the beginning of
+a field.  But the macro reader isn't a command parser; it doesn't know what
+a field is -- it's just looking for commas and skipping over quoted ones.
+First we have to fix an oversight: SET COMMAND DOUBLEQUOTING OFF should have
+worked here, but it wasn't tested in this case.  Fixed in getncm(): ckuus5.c,
+17 Mar 2003.
+
+There are only certain cases where it makes sense to treat doublequotes as
+signicant:
+
+ . An open quote must be at the beginning or preceded by a space.
+ . A close quote is only at the end or else followed by a space.
+
+This too was fixed in getncm(): ckuus5.c, 17 Mar 2003.
+
+A fix from Jeff SSL/TLS FTP data decoding.  ckcftp.c, 18 Mar 2003.
+
+Tried building C-Kermit on a Cray Y-MP with UNICOS 9.0.  "int suspend",
+declared in ckcmai.c and used in many modules, conflicts with:
+
+  unistd.h:extern int suspend __((int _Category, int _Id));
+
+The "=Dsuspend=xsuspend" trick doesn't work for this; there is no way around
+the conflict other than to rename the variable: ckcmai.c, ckutio.c,
+ckuus[35xy].c.  26 Mar 2003.  VMS and K95 not affected.
+
+OK that gets us past ckcmai.c...  Then in ckutio.c I had to add a new #ifdef
+around the LFDEVNO setting, because the Cray didn't have mkdev.h.  Could not
+find a Cray-specific manifest symbol, so I made a new makefile target (cray9)
+that sets this symbol.  Having done this I have no idea what kind of lockfile
+would be created, but I also doubt if anybody dials out from a Cray.  The
+binary should run a C90, J90, or Y-MP.  makefile, 26 Mar 2003.
+
+Added a target for SCO OSR5.0.7.  makefile, ckuver.h, 30 Mar 2003.
+
+Changed since 208:
+makefile ckuver.h ckcmai.c ckclib.c ckcftp.c ckucmd.c ckuus*.c ckutio.c.
+
+---8.0.209---
+
+From Mark Sapiro, a fix for the March 17th doubleqote fix, getncm(): ckuus5.c,
+4 Apr 2003.
+
+From Jeff, 29 Apr 2003:
+ . Corrected target for HP-UX 11.00 + OpenSSL: makefile, 
+ . Do not allow WILL AUTH before WONT START_TLS: ckctel.h ckctel.c
+ . Add hooks for SFTP and SET/SHOW SFTP: ckcdeb.h ckuusr.h ckuusr.c ckuus3.c
+ . Add SKERMIT ckuusr.h ckuusr.c
+ . Add ADM-5 terminal emulation: ckuus7.c, ckuus5.c
+ . Uncomment and update HELP SET SSH V2 AUTO-REKEY: ckuus2.c
+ . Enable IF TERMINAL-MACRO and IF STARTED-FROM-DIALER for C-Kermit: ckuus6.c
+ . Fix conflicting NOSCROLL keyword definition: ckuusr.h
+ . Set ttname when I_AM_SSH: ckuusy.c
+ . Add extended arg parsing for SSH, Rlogin, Telnet: ckuusy.c, ckuus4.c
+ . Security updates: ckuath.c, ck_ssl.c
+ . Change K95 version number to 2.2.0: ckcmai.c
+ . Save K95 term i/o state before executing keyboard macro: ckuus4.c
+ . Add tests for SSH Subsystem active during INPUT/OUTPUT/CONNECT: ckuus[45].c
+ . Enable K95 SET SSH V2 AUTO-REKEY: ckuus3.c
+
+SFTP and SET SFTP subcommands are implemented up to the case statements.
+
+Files of mine that Jeff hadn't picked up:
+  ckuver.h ckcftp.c ckutio.c ckuusx.c (just minor changes for last build-all)
+
+On 4 Jan 2003, SET RECEIVE MOVE-TO was changed to convert is argument to an
+absolute path, which made it impossible to specify a relative path, then
+move to different directories and have it apply relatively to each directory.
+Changed this as follows:
+
+ . Parser uses cmtxt() rather than cmdir() so it won't fail at parse time.
+ . If path is absolute, we fail at parse time if directory doesn't exist.
+ . In reof() we run the the path through xxstring (again, in case deferred
+   evaluation of variables is desired) and then, if not null, use it.
+ . If the directory doesn't exist, rename() fails and reof() returns -4,
+   resulting in a protocol error (this is not a change).  We do NOT create
+   the directory on the fly. 
+
+I also fixed SET SEND/RECEIVE RENAME-TO to parse with cmtxt() rather than
+cmdir(), since it's parsing a text template, not a directory name, e.g.
+"set receive rename-to file-\v(time)-v(date)-\v(pid)".  This was totally
+broken, since when I don't know.  We don't call xxstring() in this parse, so
+evaluation is always deferred -- I'd better not change this.  ckuus7.c,
+ckcfns.c, 1 May 2003.
+
+From Jeff, Sat May  3 14:15:23 2003:
+ . Pick up the right isascii definition for K95: ckctel.c
+ . malloc...  ckuath.c (new safe malloc routines for K95)
+ . Add author listing: ckuus5.c
+ . SSH Heartbeat support (K95 only): ckuus[23].c
+ . Prescan --height and --width to avoid window resizing at startup: ckuusy.c
+ . Add checks for fatal() or doexit() called from sysinit(): ckuusx.c
+ . Move some K95-specific definitions to ckoker.h: ckcdeb.h
+ . Add support for ON_CD macro in zchdir(): ckufio.c
+ . Add a command to let FTP client authenticate with SSLv2: ckcftp.c
+ . Fix parsing of FTP file facts like "UNIX.mode": ckcftp.c
+
+ON_CD will need some explaining (to be done).  It's implemented for Unix,
+VMS, WIndows, and OS/2.
+
+The FTP file facts fix came from first exposure to the new OpenBSD FTP
+server: ftp://ftp7.usa.openbsd.org/pub/os/OpenBSD/3.3/i386/
+The period in "UNIX.mode" caused an erroneous word break, adding junk to
+the filename.
+
+About the malloc changes, Jeff says "K95 is not behaving well in low memory
+environments.  I'm not sure that C-Kermit does much better.  The program does
+not crash but it certainly does not behave the way the user expects it to.
+I'm beginning to think that any malloc() error should be treated as fatal."
+
+Not visible in these changes because it's in K95-specific modules: Jeff made
+SET ATTRIBUTES OFF and SET ATTRIBUTES DATE OFF apply to XYZMODEM transfers.
+
+From Jeff, 11 May 2003:
+ . Add support for SSH Keepalive to relevant SET command (K95): ckuus3.c
+ . Reduce max overlapped i/o requests from 30 to 7 (K95): ckuus7.c
+ . Don't call sysinit() in fatal(): ckuusx.c.
+ . Some new conditionalizations for SSL module: ck_ssl.c
+
+The doublequote-parsing fixes from March and April broke the SWITCH statement,
+which is implemented by internally defining, then executing, a macro.  If I
+drop back to the old dumb handling of doublequotes, everything is fixed except
+the problem of March 17th.  But can we really expect getncm() to pre-guess
+what the parser is going to do?  getncm()'s only job is to find command
+boundaries, which are represented by commas.  Commas, however, is needed IN
+commands too.  We take a comma literally if it is quoted with \, or is inside
+a matched pair of braces, parens, or doublequotes.  It is not unreasonable to
+require a doublequote in a macro definition to be prefixed by \ when it is to
+be taken literally.  The proper response to Jason Heskett's complaint of March
+17th should have been to leave the code alone and recommand an appropriate
+form of quoting:
+
+  def TEST {
+      .foo = {X\"}
+      sho mac foo
+  }
+
+And this is what I have done.  Another reason for sticking with the old method
+is that it's explainable.  The "improved" method, even if it worked, would be
+be impossible to explain.  Btw, in testing this I noticed that the switch-test
+script made 8.0.201 dump core.  Today's version is fine.  The problem with
+quoted strings inside of IF {...} clauses and FOR and WHILE loops is fixed
+too.  Perhaps "unbroken" would be a better word.  ckuus5.c, 11 May 2003.
+
+Vace discovered that FTP MGET /EXCEPT:{... (with an unterminated /EXCEPT list)
+could crash Kermit.  Fixed in ckcftp.c, 11 May 2003.
+
+CONTINUE should not affect SUCCESS/FAILURE status.  ckuusr.c, 11 May 2003.
+
+Fixed an oversight that goes back 15 years.  While \{123} is allowed for
+decimal codes, \x{12} and \o{123} were never handled.  ckucmd.c, 11 May 2003.
+
+Added support for Red Hat <baudboy.h> and /usr/sbin/lockdev.  Supposedly this
+allows Kermit to be installed without setuid or setgid bits and still be able
+to lock and use the serial device.  Compiles and starts, but not tested.
+ckcdeb.h, makefile, ckutio.c, ckuus5.c, 16 May 2003.
+
+From Jeff: FTP ASCII send data to host when FTP /SSL was in use was broken.
+ftp_dpl is set to Clear when FTP /SSL is in use.  This was causing the data to
+be written to the socket with send() instead of the OpenSSL routines.
+ckcftp.c, ckuath.c, 21 May 2003.
+
+From Jeff: Stuff for Kerberos 524: ckcdeb.h.  Fixes for FTP; "FTP ASCII send
+data did not properly compute the end of line translations.  On Unix (and
+similar platforms) the end of line was correct for no character sets but
+incorrect when character sets were specified.  On Windows/OS2, the end of line
+was correct when character sets were specified and incorrect when they were
+not.  On MAC, both were broken.  Also, FTP Send Byte counts were incorrect
+when character sets were specified."  ckcftp.c.  17 Jun 2003.
+
+From Jeff: fixes to HTTP /AGENT: and /USER: switch action: ckcnet.c ckuus3.c
+ck_crp.c ckcftp.c ckuus2.c ckuusy.c ckuusr.c ckcnet.h, 21 Jun 2003.
+
+From Jeff: Fix SET DIALER BACKSPACE so it can override a previous SET KEY
+(e.g. from INI file): ckuus7.c.  Some SSL/TLS updates: ck_ssl.c.  HTTP support
+for VMS and other VMS improvements (e.g. a way to not have to hardwire the
+C-Kerit version number into the build script) from Martin Vorlaender:
+ckcnet.h, ckuus[r3].c, ckcdeb.h, ckvtio.c, ckcnet.c, ckvker.com.  Built on
+Solaris (gcc/ansi) and SunOS (cc/k&r).  The new VMS script tests the VMS
+version and includes HTTP support only for VMS 6.2 or later.  2 Jul 2003.
+
+Tried to build on our last VMS system but it seems to be dead.  Looks like a
+head crash (makes really loud noises, boot says DKA0 not recognized) (fooey, I
+just paid good money to renew the VMS license).  Tried building at another
+site with:
+
+  Process Software MultiNet V4.3 Rev A-X,
+  Compaq AlphaServer ES40, OpenVMS AXP V7.3
+  Compaq C V6.4-008 on OpenVMS Alpha V7.3
+
+Had to make a few corrections to ckvker.com.  But still, compilation of
+ckcnet.c bombs, indicating that the SELECT definition somehow got lost
+somewhere since the 209 release (i.e. no SELECT type is defined so it falls
+thru to "SELECT is required for this code").  But I don't see anything in
+ckcdeb.h or ckcnet.[ch] that would explain this.  Not ckvker.com either
+(putting the old one back gives the same result).  OK, I give up, maybe it's
+just that I haven't tried building it on MultiNet recently.  What about UCX?
+Aha, builds fine there except for warnings about mlook, dodo, and parser in
+ckvfio.c (because of ON_CD) -- I suppose I have #include <ckucmd.h>... (done)
+Anyhow it builds OK and the HTTP code is active and almost works (HTTP OPEN
+works; HTTP GET seems to succeed but creates an empty file every time).  Tried
+building under MultiNet at another installation; same bad result.
+
+OK so why won't it build for MultiNet?  Comparing ckcnet.c with the 209
+version, not a single #ifdef or #include is changed.  Tried building with
+p3="NOHTTP" -- builds OK, aha.  Where's the problem?  Not ckcnet.h...
+Not ckcdeb.h...  OK I give up, will revisit this next time I get time to
+do anything with the code.
+
+Later Jeff said "Martin did not implement VMS networking for the HTTP code.
+All he did was activate the #define HTTP which happens to work because his
+connections are using SSL/TLS connections.  http_inc(), http_tol(), etc have
+no support for VMS networking regardless of whether it is UCX or MULTINET.
+The vast majority of HTTP connections are not secured by SSL/TLS.  It makes no
+sense to support HTTP on VMS until someone is willing to either do the work or
+pay have the work done to implement VMS networking in that code base."  So the
+fix is to not enable HTTP for VMS after all.  Removed the CKHTTP definition
+for VMS from ckcdeb.h, 6 Jul 2003.
+
+Fixed ckvfio.c to #include <ckuusr.h> (instead of <ckucmd.h>) to pick up 
+missing prototypes.  6 Jul 2003.
+
+From Arthur Marsh: solaris2xg+openssl+zlib+srp+pam+shadow and the corresponding
+Solaris 7 target.  makefile, 6 Jul 2003.
+
+Remove duplicate #includes for <sys/stat.h>, <errno.h>, and <ctype.h> from
+ckcftp.c.  6 Jul 2003.
+
+Add -DUSE_MEMCPY to Motorola SV/68 targets because of shuffled #includes in 
+ckcftp.c.  8 Jul 2003.
+
+From Jeff: Fix problems mixing SSL and SRP without Kerberos.  Plus a few minor
+#define comment changes and a reshuffling of #defines in ckcdeb.h to allow me
+to build on X86 Windows without Kerberos.  ckcdeb.h, ck_crp.c, ckuath.c,
+10 Jul 2003.
+
+From Jeff: updated ckuat2.h and ckuath.c, 29 Jul 2003.
+
+Mats Peterson noticed that a very small Latin-1 file would be incorrectly
+identified as UCS-2 by scanfile().  Fixed in ckuusx.c, 29 Jul 2003.
+
+Fixed ACCESS macro definition to account for the fact that FIND is now a
+built-in command.  ckermit.ini, 30 Jul 2003.
+
+From Jeff: Fix for typo in urlparse() (svc/hos): ckuusy.c, 18 Aug 2003.
+
+From Jeff: Redhat9 makefile targets (needed for for OpenSSL 0.9.7):
+makefile, 19 Aug 2003.
+
+GREP /NOLIST and /COUNT did too much magic, with some undesirable fallout:
+"GREP /NOLIST /COUNT:x args" printed "file:count" for each file.  "GREP
+/COUNT:x /NOLIST args" did not print "file:count", but neither did it set the
+count variable.  Removed the magic.  Also one of the GREP switches,
+/LINENUMBERS, was out of order.  Fixed in ckuus6.c, 20 Aug 2003.
+
+From Jeff: "Reorganizing code to enable building with different subsets of
+options; a few typos corrected as well."  ckcdeb.h, ckuver.h (for RH9),
+ckcnet.c, ckuus7.c, ckuus3.c: 24 Aug 2003.
+
+Scanfile misidentified a big PDF file as text because the first 800K of it
+*was* text (most other PDF files were correctly tagged as binary).  Fixed
+by adding a check for the PDF signature at the beginning of the file.
+scanfile(): ckuusx.c, 25 Aug 2003.
+
+Ditto for PostScript files, but conservatively.  Signature at beginning of
+file must begin with "%!PS-Ado".  If it's just "%!" (or something nonstandard
+like "%%Creator: Windows PSCRIPT") we do a regular scan.  Also added "*.ps"
+to all binary filename patterns.  ckuusx.c, 4 Sep 2003.
+
+Ditto (but within #ifndef NOPCLSCAN) for PCL (<ESC>E) and PJL (<ESC>%) files,
+but no binpatterns (note: ".PCL" is the extension for TOPS-20 EXEC scripts).
+ckuusx.c, 4 Sep 2003.
+
+Added comments about OpenSSL 0.9.7 to all linux+openssl targets.
+makefile, 4 Sep 2003.
+
+From Jeff: Added - #define ALLOW_KRB_3DES_ENCRYPT.  When this symbol is defined
+at compilation Kermit will allow non-DES session keys to be used during Telnet
+Auth.  These session keys can then be used for Telnet Encrypt.  The reason
+this is not compiled on by default is that the MIT Kerberos Telnet does not
+follow the RFC for constructing keys for ENCRYPT DES when the keys are longer
+than 8 bytes in length.  ckuath.c, ckuus5.c, 4 Sep 2003.
+
+"ftp mget a b c" succeeded if one or more of the files did not exist, even
+with "set ftp error-action proceed".  This is because the server's NLST file
+list does not include any files that don't exist, so the client never even
+tries to get them.  Fortunately, the way the code is structured, this one was
+easy to fix.  ckcftp.c, 14 Sep 2003.
+
+From Jeff: Corrected code in ckcnet.c to ensure that Reverse DNS Lookups are
+not performed if tcp_rdns is OFF.  Fixed ck_krb5_getrealm() to actually return
+the realm of the credentials cache and not the default realm specified in the
+krb5.conf file.  Previously krb5_cc_get_principal() was not being called.
+Fixed ck_krb5_is_tgt_valid() to test the TGT in the current ccache and not the
+TGT constructed from the default realm.  ckcnet.c, ckuath.c, 14 Sep 2003.
+
+Marco Bernardi noticed that IF DIRECTORY could produce a false positive if
+the argument directory had previously been referenced but then removed.  This
+is because of the clever isdir() cache that was added to speed up recursion
+through big directory trees.  Changed IF DIRECTORY to make a second check
+(definitive but more expensive) if isdir() succeeds, and changed the
+directory-deleting routine, ckmkdir(), to flush the directory cache (UNIX
+only -- this also should be done in K95 but it's not critical).  This was
+done by adding a routine, clrdircache() to ckufio.c, which sets prevstat
+to -1 and prevpath[0] to NUL.  ckcfn3.c, ckuus6.c, ckufio.c, 18 Sep 2003.
+
+Marco reported the second fix still didn't work for him (even though it did
+for me).  Rather than try to figure out why, I concluded that the directory
+cache is just not safe: a directory found a second ago might have been deleted
+or renamed not only by Kermit but by some other process.  Why did I add this
+in the first place?  The log says:
+
+  Some debug logs showed that isdir() is often called twice in a row on the
+  same file.  Rather than try to sort out clients, I added a 1-element cache
+  to Unix isdir().  ckufio.c, 24 Apr 2000.
+
+Experimentation with DIR and DIR /RECURSIVE does not show this happening at
+all.  So I #ifdef'd out the directory cache (see #ifdef ISDIRCACHE in ckufio.c;
+ISDIRCACHE is not defined) and backed off the previous changes: ckufio.c,
+ckcfn3.c, ckuus6.c, 28 Sep 2003.
+
+From Jeff: Replace the compile time ALLOW_KRB_3DES_ENCRYPT with a run-time
+command SET TELNET BUG AUTH-KRB5-DES which defaults to ON: ckctel.[ch],
+ckuus[234].c, ck_crp.c, ckuath.c.  4 Oct 2003.
+
+Allow DIAL RETRIES to be any positive number, and catch negative ones.
+Also added code to check for atoi() errors (e.g. truncation).  At least on
+some platforms (e.g. Solaris) atoi() is supposed to set errno, but it
+doesn't.  ckuus3.c, ckucmd.c, 4 Oct 2003.
+
+Added /DEFAULT: to ASK-class commands (ASK, ASKQ, GETOK):
+
+ . For popups: no way to send defaults to popup_readtext() or popup_readpass().
+ . For GUI ASK[Q], pass default to gui_txt_dialog().
+ . For GUI GETOK, convert "yes" "ok" or "no" default to number for uq_ok().
+ . For Text GETOK, add default to cmkey().
+ . For Text ASK[Q], add default to cmtxt().
+ . For GETC, GETKEY, and READ: no changes.
+
+GETOK, ASK, and ASKQ with /TIMEOUT: no longer fail when the timer goes off
+if a /DEFAULT was supplied.  The GUI functions (uq_blah) don't seem to
+support timeouts.  Only the text version has been tested.  ckuus[26].c,
+4 Oct 2003.
+
+From Jeff: add /DEFAULT: for popups.  ckuus6.c. 6 Oct 2003.
+
+Change SET DIAL INTERVAL to be like SET DIAL RETRIES.  ckuus[34].c, 6 Oct 2003.
+
+Added target for HP-UX 10/11 + OpenSSL built with gcc, from Chris Cheney.
+Makefile, 12 Oct 2003.
+
+From Jeff, 6 Nov 2003:
+ . #ifdef adjustments: ckcftp.c, ckcdeb.h
+ . Fix spurious consumption of first byte(s) on Telnet connection: ckctel.c
+ . Another HP PJL test for scanfile: ckuusx.c.
+ . K95: Recognize DG4xx protected fields in DG2xx emulation: ckuus7.c.
+ . Add SSLeay version display to SHOW AUTH command: ckuus7.c
+ . Improved SET MOUSE CLEAR help text: ckuus2.c.
+ . Improved Kverbs help text: ckuus2.c (+ new IBM-3151 Kverbs).
+ . Some changes to ck_ssl.c, ckuath.c.
+
+From PeterE, 10 Nov 2003:
+ . Improved HP-UX 10/11 makefile targets for OpenSSL.
+ . #ifdef fix for OpenSSL on HP-UX: ck_ssl.c.
+
+Another new makefile from PeterE with improved and integrated HP-UX targets.
+12 Nov 2003.
+
+A couple fixes to the solaris9g+krb5+krb4+openssl+shadow+pam+zlib target
+from Jeff.  Added a solaris9g+openssl+shadow+pam+zlib target.  makefile,
+21 Nov 2003.
+
+From Jeff, 30 Nov 2003:
+ . Fix SEND /MOVE-TO: ckuusr.c.
+ . Fix K95 SET TITLE to allow quotes/braces around text: ckuus7.c.
+ . Improved "set term autodownload ?" response: ckuus5.c.
+ . Fix SHOW FEATURES to specify the protocol for encryption: ckuus5.c
+ . Make {SEND, RECEIVE} {MOVE-TO, RENAME-TO} work for XYZMODEM (K95 only).
+
+From Jeff: 7 Jan 2004:
+ . At one point Frank started to add a timer parameter to the
+   uq_txt() function but he only did it for the non-ANSI
+   compilers.  I added it for the ANSI compilers, fixed the
+   prototypes and provided a default value easily changed
+   DEFAULT_UQ_TIMEOUT: ckcker.h, ckuus[36].c, ck_ssl.c, ckcftp.c, ckuath.c.
+ . Fixed SET TERMINAL DEBUG ON (typo in variable name): ckuus7.c.
+ . Fixed BEEP INFORMATION; previously it made no sound, now uses
+   MB_ICONQUESTION.  ckuusx.c.
+
+From Ian Beckwith <ian@nessie.mcc.ac.uk> (Debianization), 7 Jan 2004:
+ . Search dir/ckermit for docs, as well as dir/kermit in cmdini(): ckuus5.c.
+ . New linux+krb5+krb4+openssl+shadow+pam target (kitchen sink minus SRP,
+   which Debian does not distribute): makefile.
+ ? Mangles the DESTDIR support in makefile to install into a staging area:
+   makefile (I didn't take this one yet).
+
+Updated copyright notices for 2004, all modules.  7 Jan 2004.
+
+Added INPUT /NOMATCH, allowing INPUT to be used for a fixed amount of time
+without attempting to match any text or patterns, so it's no longer
+necessary to "input 600 STRING_THAT_WILL_NEVER_COME".  If /NOMATCH is
+included, INPUT succeeds if the timeout expires, with \v(instatus) = 1
+(meaning "timed out"); fails upon interruption or i/o error.  ckuusr.h,
+ckuus[r24].c, 7 Jan 2004.
+
+Added SET INPUT SCALE-FACTOR <float>.  This scales all INPUT timeouts by the
+given factor, allowing time-sensitive scripts to be adjusted to changing
+conditions such as congested networks or different-speed modems without
+having to change each INPUT-class command.  This affects only those timeouts
+that are given in seconds, not as wall-clock times.  Although the scale
+factor can have a fractional part, the INPUT timeout is still an integer.
+Added this to SHOW INPUT, and added a \v(inscale) variable for it.
+ckuusr.h, ckuus[r257].c, 7 Jan 2004.
+
+undef \%a, \fverify(abc,\%a) returns 0, which makes it look as if \%a is a
+string composed of a's, b's, and/or c's, when in fact it contains nothing.
+Changed \fverify() to return -1 in this case.  ckuus4.c, 12 Jan 2004.
+
+\fcode(xxx) returned an empty string if its argument string was empty.  This
+makes it unsafe to use in arithmetic or boolean expressions.  Changed it to
+return 0 if its argument was missing, null, or empty.  ckuus4.c, 12 Jan 2004.
+
+Updated \verify() and \fcode() help text.  ckuus2.c, 12 Jan 2004.
+
+While setting up IKSD, Ian Beckwith noticed that including the --initfile:
+option caused Kermit to start parsing its own Copyright string as if it were
+the command line, and eventually crash.  I couldn't reproduce on Solaris /
+Sparc but I could in Linux / i386 (what Ian is using) -- a change from Jeff
+on 28 Apr 2003 set the command-line arg pointer to a literal empty string in
+prescan() about line 1740 of of ckuus4.c; the pointer is incremented next
+time thru the loop, resulting in random memory being referenced.  Fixed by
+setting the pointer to NULL instead of "".  ckuus4.c, 12 Jan 2004.
+
+declare \&a[999999999999999] would dump core on some platforms.  atoi()
+or whatever would truncate the dimension to maxint.  When we add 1 to the
+result, we get a negative number, which is used as an index, loop test, etc.
+Fixed both dodcl() and dclarray() to check for (n+1 < 0).  ckuus[r5].c,
+12 Jan 2004.
+
+Unix zchki() would fail on /dev/tty, which is unreasonable.  This prevented
+FOPEN /READ from reading from the terminal.  zchki() already allowed for
+/dev/null, so I added /dev/tty to the list of specials.  Ditto for FOPEN
+/WRITE and zchko().  ckufio.c 13 Jan 2004.
+
+Added untabify() routine to ckclib.[ch], 13 Jan 2004.
+Added FREAD /TRIM and /UNTABIFY.  ckuus[27].c, 13 Jan 2004.
+Added \funtabify().  ckuusr.h, ckuus[24].c, 13 Jan 2004.
+
+Dat Nguyen noticed that (setq u 'p') followed by (u) dumped core.  This was
+caused by an over-clever optimization that skipped mallocs for short
+literals, but then went on later to try to free one that hadn't been
+malloc'd.  Fixed in dosexp(): ckuus3.c, 14 Jan 2004.
+
+Catch another copyright date.  ckuus5.c, 14 Jan 2004.
+
+Fixed SWITCH to work even when SET COMMAND DOUBLEQUOTE OFF (from Mark
+Sapiro).  ckuus5.c, 15 Jan 2004.
+
+Changed version to 8.0.211 so scripts can test for recently added features.
+ckcmai.c, 15 Jan 2004.
+
+Fixed a glitch in K95 "help set port".  ckuus2.c, 20 Jan 2004.
+
+Fix from Jeff: Connections to a TLS-aware protocol which require a reconnect
+upon certificate verification failure could not reconnect if the connection
+was initiated from the command line or via a URL.  ckctel.c ckcmai.c
+ckuusr.c ckuus7.c ckuusy.c, 20 Jan 2004.
+
+From Alex Lewin: makefile target and #ifdef for Mac OS X 10.3 (Panther):
+makefile, ckcnet.c, 7 Feb 2004.
+
+Added KFLAGS to sco32v507 targets to make PTY and SSH commands work.  The
+same flags could probably also be added to earlier OSR5 targets but they
+have not been tested there.  makefile, 7 Feb 2004.
+
+Checked a complaint that "LOCAL &a" did not make array \&a[] local.  Indeed
+it did not, and can not.  You have to use the full syntax in the LOCAL
+command, "LOCAL \&a[]", or else it doesn't know it's not a macro named &a.
+7 Feb 2004.
+
+Fixed some confusion in creating IKSD database file and temp-file names.
+I was calling zfnqfp() without remembering that the path member of the
+returned struct included the filename, so to get just the directory name,
+I needed to strip the filename from the right.  ckuusy.c, 2 Mar 2004.
+
+New ckuath.c, ck_ssl.c from Jeff.  2 Mar 2004.
+
+Updated Jeff's affiliation in VERSION command text.  ckuusr.c, 2 Mar 2004.
+
+Designation changed from Dev.00 to Beta.01.  ckcmai.c, 2 Mar 2004.
+
+Fixed zrename() syslogging -- it had success and failure reversed.
+Beta.02: ckufio.c, 4 Mar 2004.
+
+Problem: when accessing IKSD via a kermit:// or iksd:// URL, and a user ID
+is given but no password, doxarg() set the password to "" instead of leaving
+it NULL, but all the tests in dourl() are for NULL.  Fixed in doxarg():
+ckuusy.c, 5 Mar 2004.
+
+The logic in dourl() about which macro to construct (login and connect,
+login and get directory listing, or login and fetch a file) was a bit off,
+so all three cases were not handled.  ckcmai.c, 5 Mar 2004.
+
+Trial Beta builds:
+ . HP-UX B.11.11 PA-RISC
+ . HP-UX B.11.23 IA64
+ . Tru64 4.0G Alpha
+ . Tru64 5.1B Alpha
+ . Debian 3.0 i386
+ . Red Hat ES 2.1 i386
+ . Slackware 9.1 i386
+ . VMS 7.3-1 Alpha + UCX 5.3
+ . VMS 7.3-1 Alpha no TCP/IP
+ . VMS 7.3 Alpha MultiNet 4.3 A-X
+ . SCO UnixWare 7.1.4 i386
+ . SCO OSR5.0.7 i386
+ . Solaris 9 Sparc
+
+Fixed compiler warning in doxarg() caused by typo (NULL instead of NUL) in
+the 5 March doxarg() edit.  ckuusy.c, 9 Mar 2004.
+
+IKSD (kermit://) command-line URLs did not work right if the client had
+already preauthenticated with Kerberos or somesuch because they tried to log
+in again with REMOTE LOGIN.  The macros constructed in doxarg() needed to
+check \v(authstate) before attempting REMOTE LOGIN.  ckcmai.c, 10 Mar 2004.
+
+Added ckuker.nr to x.sh (ckdaily upload) and updated ckuker.nr with current
+version number and dates.  10 Mar 2004.
+
+Replaced hardwired references to /usr/local in makefile with $(prefix)
+(which defaults to /usr/local, but can be overridden on the command line),
+suggested by Nelson Beebe for use with Configure.  10 Mar 2004.
+
+From Nelson Beebe: In the Kermit makefile in the install target commands,
+line 981 reads:
+
+        cp $(BINARY) $(DESTDIR)$(BINDIR)/kermit || exit 1;\
+
+Could you please add this line before it:
+
+        rm -f $(DESTDIR)$(BINDIR)/kermit;\
+
+Some sites (mine included) keep multiple versions of software around,
+with hard links between $(prefix)/progname and $(prefix)/progname-x.y.z.
+Failure to remove the $(prefix)/progname at "make install" time then
+replaces the old $(prefix)/progname-x.y.z with the new one, destroying
+an old version that the site wanted to be preserved.  makefile, 10 Mar 2004.
+
+Minor syntax and typo fixes (mostly prototypes): ckcdeb.h, ckcfns.c,
+ckclib.c, ckufio.c, ckuusr.h, ckuusx.c, 10 Mar 2004.  (I still have a few
+more to do.)
+
+Added CC=$(CC) CC2=$(CC2) to many (but not all) makefile targets that
+reference other makefile targets.  On some platforms (notably AIX, Solaris,
+SunOS) there are specific targets for different compilers, so I skipped
+those.  makefile, 10 Mar 2004.
+
+Added error checking to kermit:// URL macros, so they don't plow ahead
+after the connection is closed.  ckcmai.c, 11 Mar 2004.
+
+Added FreeBSD 4.9 and 5.1 targets (only the herald is affected).
+makefile, ckuver.h, 11 Mar 2004.
+
+Added "LIBS=-lcrypt" to bsd44 targets since nowadays crypt is almost always
+unbundled from libc.  Also added explanatory notes.  makefile, 11 Mar 2004.
+
+Changed MANDIR to default to $(manroot)/man/man1, and manroot to default
+to $(prefix).  More adding of CC=$(CC) clauses: {Free,Net,Open}BSD, 4.4BSD.
+makefile, 11 Mar 2004.
+
+Miscellaneous cleanups: ckuusx.c, ckcnet.c, ckufio.c, 11 Mar 2004.
+
+Corrected the check in the linux target to see if /usr/include/crypt.h
+exists, and if so to define HAVE_CRYPT_H, which is used in ckcdeb.h to
+#include <crypt.h> to get the prototype for crypt() and prevent bogus
+conversions on its return type on 64-bit platforms (the previous test wasn't
+quite right and the resulting symbol wasn't spelled right).  makefile,
+12 Mar 2004.
+
+From Jeff, 14 Mar 2004:
+ . Initialize localuidbuf[] in tn_snenv(): ckctel.c.
+ . Remove remote-mode checks in hupok() for K95G only (why?): ckuus3.c.
+ . Add help text for new K95-only TYPE /GUI switches: ckuus2.c.
+ . TYPE /GUI parsing, ...: ckuusr.c.
+ . TYPE /GUI action, dotype(): ckuus6.c
+ . Change Jeff's affiliation: most modules.
+
+20 Mar 2004: Looked into adding long file support, i.e. handling files more
+than 2GB (or 4GB) long.  Discovered very quickly this would be a major
+project.  Each platform has a different API, or environment, or transition
+plan, or whatever -- a nightmare to handle in portable code.  At the very
+least we'll need to convert a lot of Kermit variables from long or unsigned
+long to some new Kermit type, which in turn is #defined or typedef'd
+appropriately for each platform (to off_t or size_t or whatever).  Then we
+have to worry about the details of open() vs fopen(); printf() formats (%lld
+vs %Ld vs %"PRId64"...), platforms like HP-UX where you might have to use
+different APIs for different file systems on the same computer, etc.  We'll
+need to confront this soon, but let's get a good stable 8.0.211 release out
+first!  Meanwhile, for future reference, here are a few articles:
+
+General: http://freshmeat.net/articles/view/709/
+Linux:   http://www.ece.utexas.edu/~luo/linux_lfs.html
+HP-UX:   http://devrsrc1.external.hp.com/STK/partner/lg_files.pdf
+Solaris: http://wwws.sun.com/software/whitepapers/wp-largefiles/largefiles.pdf
+
+Looked into FTP timeouts.  It appears I can just call empty() (which is
+nothing more than a front end for select()) with the desired timeout before
+any kind of network read.  If it returns <= 0, we have a timeout.  This is
+not quite the same as using alarm() / signal() around a recv() (which could
+get stuck) but alarm() / signal() are not not used in the FTP module and are
+not naturally portable to Windows, but select() is already in use in the FTP
+module for both Unix and Windows.  This form of timeout could be used
+portably for both command response and data reads.  What about writes to the
+command or data socket?  They can get stuck for hours and hours without
+returning too, but the select() approach won't help here -- we need the
+actual send() or recv() to time out, or be wrapped in an alarm()/signal()
+kind of mechanism.  But if we can do that for sends, we can also do it for
+receives.  Better check with Jeff before I start programming anything.
+20 Mar 2004.
+
+Later: Decided to postpone the above two projects (ditto IPv6) until after
+8.0.211 is released because both will have major impacts on portability.
+Grumble: all i/o APIs should have been designed from the beginning with a
+timeout parameter.  To this day, hardly any have this feature.
+
+3-4 Apr 2004: More 8.0.211 Beta.02+ test builds:
+
+ . FreeBSD 3.3
+ . FreeBSD 4.4
+ . Linux Debian 2.1
+ . Linux RH 6.1
+ . Linux RH 7.1
+ . Linux RH 7.2
+ . Linux RH 9 (with 84 different combinations of feature selection)
+ . Linux SuSE 6.4
+ . Linux SuSE 7.0
+ . NetBSD 1.4.1
+ . NetBSD 1.5.2
+ . OpenBSD 2.5
+ . OpenBSD 3.0
+ . QNX 4.25
+ . SCO UnixWare 2.1.3
+ . SCO UnixWare 7.1.4
+ . SCO OpenServer 5.0.7
+ . SCO XENIX 2.3.4 (no TCP)
+
+Changes needed: None.
+
+Problem: SCO XENIX 2.3.4 network build failed in the FTP module with
+header-file syntax and conflicting-definitions trouble.  I'm not going to
+try to fix it; 8.0.209 built OK with FTP, so we'll just keep that one
+available.
+
+Got access to VMS 8.1 on IA64.  Building the nonet version of C-Kermit
+required minor modifications to ckvvms.h, ckv[ft]io.c, and ckvcon.c, to
+account for a third architecture.  Also to SHOW FEATURES in ckuus5.c.  Once
+that was done, the UCX 5.5 version built OK too.  Starts OK, makes Telnet
+connection OK, sends files.  Has some obvious glitches though -- "stat"
+after a file transfer reports 0 elapsed time (in fact it was 00:09:48) and
+1219174400 cps (when in fact it was 10364).  This doesn't happen on the
+Alpha.  Btw, the IA64 binary is twice as big as the Alpha one.  Changed
+to Beta.03.  5 Apr 2004.
+
+Fixed the ckdaily script to include the makefile and man page in the Zip
+file (they were not included because the Zip file was intended mainly for
+VMS users, but some Unix users prefer Zip to tar.gz).  6 Apr 2004.
+
+Traced problems in VMS/IA64 statistics report to rftimer()/gftimer() in
+ckvtio.c, which use sys$ and lib$ calls to figure elapsed time.  These work
+on VAX and Alpha but not IA64.  Sent a report to the chief engineer of the
+IA64 VMS port; he says it's probably a bug in VMS 8.1 (which is not a real
+release); he'll make sure it's fixed in 8.2.  As an experiment, tried
+swapping in the Unix versions of these routines (which call gettimeofday()
+etc).  They seem work just fine (it hung a couple times but I think that's
+because the underlying system hung too; trying it later on a new connection,
+it was fine; however I noticed a BIG discrepancy in throughput between
+sending and receiving).  Moved definitions for VMS64BIT and VMSI64 to
+ckcdeb.h so all modules can use them and added them to the SHOW FEATURES
+display.  Added VMSV80 definition to build procedure.  Beta.03+.  ckcdeb.h,
+ckcuus5.c, ckcvvms.h, ckvtio.c, ckvker.com, 6 Apr 2004.
+
+While doing the build-all, I noticed the VMS version did not build with
+Multinet or older UCX versions, always with the same errors -- undeclared
+variables, undefined symbols, all TCP/IP related.  This didn't happen a
+couple weeks ago...  Somehow the order of #includes was messed up --
+ckuusr.h depended on symbols that are defined in ckcnet.h, but ckcnet.h
+was being included after ckuusr.h...  this was compounded by two missing
+commas in ckvker.com.  11 Apr 2004.
+
+Removed Beta designation, released as 8.0.211, 10 Apr 2004.
+
+---8.0.211---
+
+I had somehow lost the edit to ckutio.c that changed the UUCP lockfile for
+Mac OS X from /var/spool/uucp to /var/spool/lock.  So I slipped it in and
+re-uploaded version 8.0.211.  You can tell the difference because SHOW
+VERSIONS has a 17 Apr 2004 for the Communications I/O module.  Also the 10.3
+executable now has a designer banner: "Mac OS X 10.3".  makefile, ckuver.h,
+ckutio.c, ckuus[45].c, 17 Apr 2004.
+
+***********************
diff --git a/ckermit-8.0.211/ckcasc.h b/ckermit-8.0.211/ckcasc.h
new file mode 100644
index 0000000..c7c32cc
--- /dev/null
+++ b/ckermit-8.0.211/ckcasc.h
@@ -0,0 +1,69 @@
+/*
+  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, 2004,
+    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 CR    13        /* Carriage Return Ctrl-M */
+#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 EM    25        /* Ctrl-Y */
+#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 */
diff --git a/ckermit-8.0.211/ckcbwr.txt b/ckermit-8.0.211/ckcbwr.txt
new file mode 100644
index 0000000..5e70e65
--- /dev/null
+++ b/ckermit-8.0.211/ckcbwr.txt
@@ -0,0 +1,1467 @@
+
+                      C-Kermit 8.0 General Hints and Tips
+
+     Frank da Cruz
+     [1]The Kermit Project, [2]Columbia University
+
+   As of: C-Kermit 8.0.211, 17 March 2003
+   This page last updated: Sat Apr 10 16:37:37 2004 (New York USA Time)
+
+     IF YOU ARE READING A PLAIN-TEXT version of this document, it is a
+     plain-text dump of a Web page. You can visit the original (and
+     possibly more up-to-date) Web page here:
+
+  [3]http://www.columbia.edu/kermit/ckcbwr.html
+
+   This document contains platform-independent C-Kermit hints and tips.
+   Also see the platform-specific C-Kermit hints and tips document for
+   your platform, for example:
+
+  [4]http://www.columbia.edu/kermit/ckubwr.html
+
+   for Unix. This document also applies to [5]Kermit 95 for Windows,
+   which is based on C-Kermit.
+
+   [ [6]C-Kermit ] [ [7]TUTORIAL ]
+    ________________________________________________________________________
+
+  CONTENTS
+
+   0. [8]PATCHES
+   1. [9]INCOMPATIBLE CHANGES
+   2. [10]THE C-KERMIT COMMAND PARSER
+   3. [11]MULTIPLE SESSIONS
+   4. [12]NETWORK CONNECTIONS
+   5. [13]MODEMS AND DIALING
+   6. [14]DIALING HINTS AND TIPS
+   7. [15]TERMINAL SERVERS
+   8. [16]TERMINAL EMULATION
+   9. [17]KEY MAPPING
+  10. [18]FILE TRANSFER
+  11. [19]SCRIPT PROGRAMMING
+    ________________________________________________________________________
+
+  0. PATCHES
+
+   [ [20]Top ] [ [21]Contents ] [ [22]Next ]
+
+   Source-level patches for C-Kermit 8.0.211:
+
+     (None)
+    ________________________________________________________________________
+
+  1. INCOMPATIBLE CHANGES
+
+   [ [23]Top ] [ [24]Contents ] [ [25]Next ]
+
+   These are not necessarily exhaustive lists.
+
+  1.1. C-Kermit 6.0
+
+   C-Kermit 6.0 was released 6 September 1996 and is completely
+   documented in [26]Using C-Kermit, 2nd Edition. The following
+   incompatible changes were made in C-Kermit 6.0:
+
+     * Unless you tell C-Kermit otherwise, if a serial or network
+       connection seems to be open, and you attempt to EXIT or to open a
+       new connection, C-Kermit warns you that an active connection
+       appears to be open and asks you if you really want to close it. If
+       you do not want these warnings, add SET EXIT WARNING OFF to your
+       customization file or script, or give this command at the prompt.
+     * The default for SET { SEND, RECEIVE } PATHNAMES was changed from
+       ON to OFF, to prevent unexpected creation of directories and
+       depositing of incoming files in places you might not know to look.
+     * The default for SET FILE INCOMPLETE was changed from DISCARD to
+       KEEP to allow for file transfer recovery.
+     * The default file-transfer block-check is now 3, rather than 1. If
+       the other Kermit does not support this, the two will drop back to
+       type 1 automatically unless the other Kermit fails to follow the
+       protocol specification.
+     * The default flow-control is now "auto" ("do the right thing for
+       each type of connection"), not Xon/Xoff.
+     * Backslash (\) is no longer a command continuation character. Only
+       - (hyphen, dash) may be used for this in C-Kermit 6.0 and later.
+     * Negative INPUT timeout now results in infinite wait, rather than 1
+       second.
+
+  1.2. C-Kermit 7.0
+
+   C-Kermit 7.0 was released 1 January 2000. Its new features are
+   documented in the C-Kermit 7.0 Supplement,
+   [27]http://www.columbia.edu/kermit/ckermit2.html. The following
+   incompatible changes were made in C-Kermit 7.0:
+     * The "multiline GET" command is gone. Now use either of the
+       following forms instead:
+  get remote-name local-name
+  get /as-name:local-name remote-name
+       If either name contains spaces, enclose it in braces (or, in
+       C-Kermit 8.0, doublequotes).
+     * To include multiple file specifications in a GET command, you must
+       now use MGET rather than GET:
+  mget file1 file2 file3 ...
+     * C-Kermit 7.0 and later use FAST Kermit protocol settings by
+       default. This includes "unprefixing" of certain control
+       characters. Because of this, file transfers that worked with
+       previous releases might not work in the new release especially
+       against a non-Kermit-Project Kermit protocol implementation (but
+       it is more likely that they will work, and much faster). If a
+       transfer fails, you'll get a context-sensitive hint suggesting
+       possible causes and cures. Usually SET PREFIXING ALL does the
+       trick.
+     * By default C-Kermit 7.0 and later send files in text or binary
+       mode by looking at each file to see which is the appropriate mode.
+       To restore the previous behavior, put SET TRANSFER MODE MANUAL and
+       the desired SET FILE TYPE (TEXT or BINARY) in your C-Kermit
+       initialization file.
+     * The RESEND and REGET commands automatically switch to binary mode;
+       previously if RESEND or REGET were attempted when FILE TYPE was
+       TEXT, these commands would fail immediately, with a message
+       telling you they work only when the FILE TYPE is BINARY. Now they
+       simply do this for you.
+     * SET PREFIXING CAUTIOUS and MINIMAL now both prefix linefeed (10
+       and 138) in case rlogin, ssh, or cu are "in the middle", since
+       otherwise <LF>~ might appear in Kermit packets, and this would
+       cause rlogin, ssh, or cu to disconnect, suspend,escape back, or
+       otherwise wreck the file transfer. Xon and Xoff are now always
+       prefixed too, even when Xon/Xoff flow control is not in effect,
+       since unprefixing them has proven dangerous on TCP/IP connections.
+     * In UNIX, VMS, Windows, and OS/2, the DIRECTORY command is built
+       into C-Kermit itself rather than implemented by running an
+       external command or program. The built-in command might not behave
+       the way the platform-specific external one did, but many options
+       are available for customization. Of course the underlying
+       platform-specific command can still be accessed with "!", "@", or
+       "RUN" wherever the installation does not forbid. In UNIX, the "ls"
+       command can be accessed directly as "ls" in C-Kermit.
+     * SEND ? prints a list of switches rather than a list of filenames.
+       If you want to see a list of filenames, use a (system-dependent)
+       construction such as SEND ./? (for UNIX, Windows, or OS/2), SEND
+       []? (VMS), etc.
+     * In UNIX, OS-9, and Kermit 95, the wildcard characters in previous
+       versions were * and ?. In C-Kermit 7.0 they are *, ?, [, ], {, and
+       }, with dash used inside []'s to denote ranges and comma used
+       inside {} to separate list elements. If you need to include any of
+       these characters literally in a filename, precede each one with
+       backslash (\).
+     * SET QUIET { ON, OFF } is now on the command stack, just like SET
+       INPUT CASE, SET COUNT, SET MACRO ERROR, etc, as described on p.458
+       of [28]Using C-Kermit, 2nd Edition. This allows any macro or
+       command file to SET QUIET ON or OFF without worrying about saving
+       and restoring the global QUIET value. For example, this lets you
+       write a script that tries SET LINE on lots of devices until it
+       finds one free without spewing out loads of error messages, and
+       also without disturbing the global QUIET setting, whatever it was.
+     * Because of the new "." operator (which introduces assignments),
+       macros whose names begin with "." can not be invoked "by name".
+       However, they still can be invoked with DO or \fexecute().
+     * The syntax of the EVALUATE command has changed. To restore the
+       previous syntax, use SET EVALUATE OLD.
+     * The \v(directory) variable now includes the trailing directory
+       separator; in previous releases it did not. This is to allow
+       constructions such as:
+  cd \v(dir)data.tmp
+       to work across platforms that might have different directory
+       notation, such as UNIX, Windows, and VMS.
+     * Prior to C-Kermit 7.0, the FLOW-CONTROL setting was global and
+       sticky. In C-Kermit 7.0, there is an array of default flow-control
+       values for each kind of connection, that are applied automatically
+       at SET LINE/PORT/HOST time. Thus a SET FLOW command given before
+       SET LINE/PORT/HOST is likely to be undone. Therefore SET FLOW can
+       be guaranteed to have the desired effect only if given after the
+       SET LINE/PORT/HOST command.
+     * Character-set translation works differently in the TRANSMIT
+       command when (a) the file character-set is not the same as the
+       local end of the terminal character-set, or (b) when the terminal
+       character-set is TRANSPARENT.
+
+  1.3. C-Kermit 8.0
+
+   The following incompatible changes were made in C-Kermit 8.0:
+     * C-Kermit now accepts doublequotes in most contexts where you
+       previously had to use braces to group multiple words into a single
+       field, or to force inclusion of leading or trailing blanks. This
+       might cause problems in contexts where you wanted the doublequote
+       characters to be taken literally. Consult [29]Section 5 of the
+       [30]C-Kermit 8.0 Update Notes for further information.
+     * Using the SET HOST command to make HTTP connections is no longer
+       supported. Instead, use the new [31]HTTP OPEN command.
+    ________________________________________________________________________
+
+  2. THE C-KERMIT COMMAND PARSER
+
+   [ [32]Top ] [ [33]Contents ] [ [34]Next ] [ [35]Previous ]
+
+   Various command-related limits are shown in the following table, in
+   which the sample values are for a "large memory model" build of
+   C-Kermit, typical for modern platforms (Linux, Solaris, AIX, VMS,
+   etc). You can see the values for your version of Kermit by giving the
+   SHOW FEATURES command. The maximum length for a Kermit command (CMDBL)
+   also determines the maximum length for a macro definition, since
+   DEFINE is itself a command. The maximum length for a variable name is
+   between 256 and 4096 characters, depending on the platform; for array
+   declarations and references, that includes the subscript.
+       ______________________________________________________________
+
+   Item Symbol Sample
+   Value Definition
+   Number of characters in a command CMDBL 32763 ckucmd.h
+   Number of chars in a field of a command    ATMBL 10238 ckucmd.h
+   Nesting level for command files MAXTAKE 54   ckuusr.h
+   Nesting level for macros MACLEVEL 128 ckuusr.h
+   Nesting level for FOR / WHILE loops FORDEPTH 32 ckuusr.h
+   Number of macros MAC_MAX 16384 ckuusr.h
+   Size of INPUT buffer INPBUFSIZ 4096 ckuusr.h
+   Maximum files to match a wildcard MAXWLD    102400 ckcdeb.h
+   Filespecs in MSEND command MSENDMAX 1024 ckuusr.h
+   Length for GOTO target label LBLSIZ 50 ckuusr.h
+   \fexecute() recursion depth limit CMDDEP 64 ckucmd.h
+       ______________________________________________________________
+
+   If you need to define a macro that is longer than CMDBL, you can break
+   the macro up into sub-macros or rewrite the macro as a command file.
+   In a pinch you can also redefine CMDBL and recompile C-Kermit. All of
+   these numbers represent tradeoffs: the bigger the number, the more
+   "powerful" Kermit in the corresponding area, but also the bigger the
+   program image and possibly disk footprint, and the longer it takes to
+   load and initialize.
+
+   In the interactive command parser:
+
+     * EMACS- or VI-style command line editing is not supported.
+     * Editing keys are hardwired (Ctrl-U, Ctrl-W, etc).
+
+   If you interrupt C-Kermit before it has issued its first prompt, it
+   will exit. This means that you cannot interrupt execution of the
+   initialization file, or of an "application file" (file whose name is
+   given as the first command-line argument), or of an alternative
+   initialization file ("-y filename"), and get to the prompt. There is,
+   however, one exception to this rule: you *can* interrupt commands --
+   including TAKE commands -- given in the '-C "command list"'
+   command-line argument and -- if there were no action commands among
+   the command-line arguments -- you will be returned to the C-Kermit
+   prompt. So, for example, if you want to start C-Kermit in such a way
+   that it executes a command file before issuing its first prompt, and
+   you also want to be able to interrupt the command file and get to the
+   prompt, include a TAKE command for the desired command in the -C
+   argument, for example:
+
+  kermit -C "take dial.scr"
+
+   At the command prompt, if you use the backslash (\) prefix to enter a
+   control character, space, or question mark into a command literally,
+   the backslash disappears and is replaced by the quoted character. If
+   it was a control character, it is shown as a circumflex (^). This
+   allows editing (backspace, delete, Ctrl-W) to work correctly even for
+   control characters.
+
+   Priot to C-Kermit 8.0, the only way to include a comma literally in a
+   macro definition -- as opposed to having it separate commands within
+   the definition -- is to enter its ASCII value (44) in backslash
+   notation, e.g.:
+
+  DEFINE ROWS RUN MODE CO80\{44}\%1
+
+   In C-Kermit 8.0 you can use constructions like this:
+
+  DEFINE ROWS RUN MODE "CO80,\%1"
+
+   If you quote special characters in a filename (e.g. in the SEND
+   command), filename completion may seem to work incorrectly. For
+   example, if you have a file whose name is a*b (the name really
+   contains an asterisk), and you type "send a\\*<ESC>", the "b" does not
+   appear, nor will Ctrl-R redisplay the completed name correctly. But
+   internally the file name is recognized anyway.
+
+   Question-mark help does not work during execution of an ASKQ command.
+   The question marks are simply accepted as text.
+
+   In OUTPUT commands only, \B sends a BREAK signal, \L sends a Long
+   BREAK signal, and \N sends a NUL (ASCII 0). BREAK and Long BREAK are
+   special signals, not characters, and NUL is a character that normally
+   cannot be included in a C string, since it is the C string terminator.
+   If you really want to output a backslash followed by a B, an L, or an
+   N (as is needed to configure certain modems, etc), double the
+   backslash, e.g. "output \\B". In C-Kermit 7.0 or later, you can disarm
+   and re-arm the special OUTPUT-command escapes (\B, \L, and \N) with
+   SET OUTPUT SPECIAL-ESCAPES { OFF, ON }.
+
+   When using the command-line processor ("kermit -l /dev/tty00 -b
+   19200", etc), note that in some cases the order of the command-line
+   options makes a difference, contrary to the expectation that order of
+   command-line options should not matter. For example, the -b option
+   must be given after the -l option if it is to affect the device
+   specified in the -l option.
+    ________________________________________________________________________
+
+  3. MULTIPLE SESSIONS
+
+   [ [36]Top ] [ [37]Contents ] [ [38]Next ] [ [39]Previous ]
+
+   C-Kermit 7.0 and earlier do not support multiple sessions. When you
+   SET LINE (or SET PORT, same thing) to a new device, or SET HOST to a
+   new host, the previous SET LINE device or network host connection is
+   closed, resulting in hangup of the modem or termination of the network
+   connection. In windowing environments like HP-VUE, NeXTSTEP, Windows,
+   OS/2, etc, you can run separate copies of Kermit in different windows
+   to achieve multiple sessions.
+
+   To achieve multiple sessions through a single serial port (e.g. when
+   dialing up), you can install SLIP or PPP on your computer and then use
+   C-Kermit's TCP/IP support over the SLIP or PPP connection, assuming
+   you also have TCP/IP networking installed on your computer.
+
+   C-Kermit 8.0 has the same restriction on SET LINE and SET HOST
+   sessions: only one regular session (dialout, Telnet, etc) can be open
+   at a time. However, version 8.0 adds two new kinds of sessions: FTP
+   and HTTP; one or both of these can be open at the same as a regular
+   session.
+    ________________________________________________________________________
+
+  4. NETWORK CONNECTIONS
+
+   [ [40]Top ] [ [41]Contents ] [ [42]Next ] [ [43]Previous ]
+
+  FTP Client Bugs
+
+   The Unix C-Kermit 8.0.206 FTP client had the following bugs at the
+   time most of the 8.0.206 binaries were built for the C-Kermit 8.0
+   CDROM:
+
+    1. FTP MGET fails when directory segments contain wildcards, as in
+       "ftp mget */data/*.dat". Work around by doing a separate MGET for
+       each source directory.
+    2. FTP MGET can fail or produce random side effects if you have a
+       TMPDIR or CK_TMP environment variable definition in effect, or a
+       SET TEMP-DIRECTORY value, longer than 7 characters. Work around by
+       giving a SET TEMP-DIRECTORY command with a short value, such as
+       "/tmp".
+
+   These two bugs are fixed in the source code that is included on the
+   CDROM, and also in Kermit 95 2.1.1. You can tell if a C-Kermit 8.0.206
+   binary has these fixes by typing SHOW VERSION; if it says "FTP Client,
+   8.0.200, 24 Oct 2002" it has the fixes; if the edit number is less
+   that 200, it doesn't, in which case can build a new binary from the
+   source code (or contact us and we'll try to get get one for you).
+
+  Making TCP/IP Connections Can Take a Long Time
+
+   The most frequently asked question in many newsgroups is "Why does it
+   take such a long time to make a Telnet connection to (or from) my
+   (e.g.) Linux PC?" (this applies to Kermit as well as to regular Telnet
+   clients):
+
+    1. Most Telnet servers perform reverse DNS lookups on the client for
+       security and/or logging reasons. If the Telnet client's host
+       cannot be found by the server's local DNS server, the DNS request
+       goes out to the Internet at large, and this can take quite some
+       time. The solution to this problem is to make sure that both
+       client and host are registered in DNS.
+    2. C-Kermit itself performs reverse DNS lookups unless you tell it
+       not to. This is to allow C-Kermit to let you know which host it is
+       actually connected to in case you have made a connection to a
+       "host pool" (multihomed host). You can disable C-Kermit's reverse
+       DNS lookup with SET TCP REVERSE-DNS-LOOKUP OFF.
+    3. C-Kermit 7.0 and later strictly enforce Telnet protocol rules. One
+       such rule is that certain negotiations must be responded to. If
+       C-Kermit sends a such a negotiation and the host does not respond,
+       C-Kermit waits a long time for the reply (in case the network is
+       congested or the host is slow), but eventually will time out. To
+       eliminate the waits (and therefore risk possible protocol
+       mismatches -- or worse -- between Telnet client and server), tell
+       C-Kermit to SET TELNET WAIT OFF (or include the /NOWAIT switch
+       with the TELNET command).
+
+  The Rlogin Client
+
+   In multiuser operating systems such as UNIX and VMS, TCP/IP Rlogin
+   connections are available only to privileged users, since "login" is a
+   privileged socket. Assuming you are allowed to use it in the first
+   place, it is likely to behave differently depending on what type of
+   host you are rlogging in to, due to technical reasons having to do
+   with conflicting interpretations of RFC793 (Out-Of-Band Data) and
+   Rlogin (RFC1122)... "Specifically, the TCP urgent pointer in BSD
+   points to the byte after the urgent data byte, and an RFC-compliant
+   TCP urgent pointer points to the urgent data byte. As a result, if an
+   application sends urgent data from a BSD-compatible implementation to
+   an [44]RFC-1122 compatible implementation then the receiver will read
+   the wrong urgent data byte (it will read the byte located after the
+   correct byte in the data stream as the urgent data byte)." Rlogin
+   requires the use of OOB data while Telnet does not. Therefore, it is
+   possible for Telnet to work between all systems while BSD and System V
+   TCP/IP implementations are almost always a bad mix.
+
+  The Telnet Client
+
+   On a TCP/IP TELNET connection, you should normally have PARITY set to
+   NONE and (except in VMS C-Kermit) FLOW-CONTROL also set to NONE. If
+   file transfer does not work with these settings (for example, because
+   the remote TELNET server only gives a 7-bit data path), use SET PARITY
+   SPACE. Do not use SET PARITY MARK, EVEN, or ODD on a TELNET connection
+   -- it interferes with TELNET protocol.
+
+   If echoing does not work right after connecting to a network host or
+   after dialing through a TCP/IP modem server, it probably means that
+   the TELNET server on the far end of the connection is executing the
+   TELNET protocol incorrectly. After initially connecting and
+   discovering incorrect echoing (characters are echoed twice, or not at
+   all), escape back, give the appropriate SET DUPLEX command (FULL or
+   HALF), and then CONNECT again. For a consistently misbehaving
+   connection, you can automate this process in a macro or TAKE file.
+
+   TELNET sessions are treated just like serial communications sessions
+   as far as "terminal bytesize" and "command bytesize" are concerned. If
+   you need to view and/or enter 8-bit characters during a TELNET
+   session, you must tell C-Kermit to SET TERMINAL BYTESIZE 8, SET
+   COMMAND BYTESIZE 8, and SET PARITY NONE.
+
+   If you SET TELNET DEBUG ON prior to making a connection, protocol
+   negotiations will be displayed on your screen. You can also capture
+   them in the debug log (along with everything else) and then extract
+   them easily, since all Telnet negotiations lines begin with
+   (uppercase) "TELNET".
+    ________________________________________________________________________
+
+  5. MODEMS AND DIALING
+
+   [ [45]Top ] [ [46]Contents ] [ [47]Next ] [ [48]Previous ]
+
+   External modems are recommended because:
+
+     * They don't need any special drivers.
+     * They are less likely to interfere with normal operation of your
+       computer.
+     * You can use the lights and speaker to troubleshoot dialing.
+     * You can share them among all types of computers.
+     * You can easily turn them off and on when power-cycling seems
+       warranted.
+     * They are more likely to have manuals.
+
+   Modems can be used by C-Kermit only when they are visible as or
+   through a regular serial port device. Certain modems can not be used
+   in this normal way on many kinds of computers: Winmodems, RPI modems,
+   Controllerless modems, the IBM Mwave, etc; all of these require
+   special drivers that perform some, most, or all of the modem's
+   functions in software. Such drivers are generally NOT available in
+   UNIX or other non-Windows (or non-OS/2, in the case of the Mwave)
+   platforms.
+
+   In order to dial a modem, C-Kermit must know its repertoire of
+   commands and responses. Each modem make and model is likely to have a
+   different repertoire. Since Kermit has no way of knowhing which kind
+   of modem will be dialed, normally you have to tell it with a SET MODEM
+   TYPE command, e.g.:
+
+  set modem type usrobotics
+  set line /dev/cua0
+  set speed 57600
+  dial 7654321
+
+   In the early days, there was a wide variety of modems and command
+   languages. Nowadays, almost every modem uses the Hayes AT command set
+   (but with some differences in the details) and its startup
+   configuration includes error correction, data compression, and
+   hardware (RTS/CTS) flow control. As long as C-Kermit is capable of
+   hardware flow control (as it is on many, but not all, the platforms
+   where it runs, since some operating systems don't support it), the
+   modem can be dailed immediately, without lengthy configuration
+   dialogs, and in fact this is what SET MODEM TYPE GENERIC-HIGH-SPEED
+   does. In C-Kermit 8.0, GENERIC-HIGH-SPEED has become the default modem
+   type, so now it is usually possible to SET LINE, SET SPEED, and DIAL
+   without having to identify your modem. If this doesn't work, of
+   course, then you might have to fall back to the tradiational method:
+   Give a SET MODEM TYPE for a specific modem first, then SET LINE, SET
+   SPEED, and DIAL.
+
+   An important change in C-Kermit 6.0 is that when you give a SET MODEM
+   TYPE command to tell Kermit what kind of modem you have, Kermit also
+   sets a number of other modem-related parameters automatically from its
+   internal modem database. Thus, the order in which you give
+   modem-related commands is significant, whereas in prior releases they
+   could be given in any order.
+
+   In particular, MODEM SPEED-MATCHING is set according to whether the
+   modem is known to be capable of speed buffering. SET MODEM TYPE
+   HAYES-2400 automatically turns SPEED-MATCHING ON, because when the
+   Hayes 2400 reports a particular speed in its CONNECT message, that
+   means its interface speed has changed to that speed, and C-Kermit's
+   must change accordingly if it is to continue communicating. This might
+   cause some confusion if you use "set modem type hayes" for dialing a
+   more advanced type of modem.
+
+   The new default for flow control is "auto", meaning "do the right
+   thing for each type of connection". So (for example) if your version
+   of C-Kermit supports SET FLOW RTS/CTS and your modem also supports
+   RTS/CTS, then Kermit automatically sets its flow control to RTS/CTS
+   and set modem's flow control to RTS/CTS too before attempting to use
+   the modem.
+
+   For these reasons, don't assume that "set modem type hayes" should be
+   used for all modems that uses the Hayes AT command set. "set modem
+   type hayes" really does mean Hayes 1200 or 2400, which in turn means
+   no hardware flow control, and no speed buffering. This choice will
+   rarely work with a modern high-speed modem.
+    ________________________________________________________________________
+
+  6. DIALING HINTS AND TIPS
+
+   [ [49]Top ] [ [50]Contents ] [ [51]Next ] [ [52]Previous ]
+
+   If you have a high-speed, error-correcting, data-compressing,
+   speed-buffering modem, you should fix the modem's interface speed as
+   high as possible, preferably (at least) four times higher than its
+   maximum connection (modulation) speed to allow compression to work at
+   full advantage. In this type of setup, you must also have an effective
+   means of flow control enabled between C-Kermit and the modem,
+   preferably hardware (RTS/CTS) flow control. On platforms that do not
+   support hardware flow control, it is usually possible to select
+   software flow control (Xon/Xoff), and C-Kermit will do its best to set
+   the modem for local Xon/Xoff flow control too (but then, of course,
+   Ctrl-S and Ctrl-Q characters can not be transmitted on the
+   connection).
+
+   If you are having trouble dialing your modem, SET DIAL DISPLAY ON to
+   watch the dialing interactions between C-Kermit and your modem.
+   Consult Chapters 3-4 of [53]Using C-Kermit (2nd Ed) for modem-dialing
+   troubleshooting instructions. The following sections offer some
+   addtional hints and tips.
+
+  6.1. Syntax
+
+   If you want to dial a number that starts with #, you'll need to quote
+   the "#" character (as \# or \{35}), since it is also a comment
+   introducer:
+
+  C-Kermit>dial #98765421-1-212-5551212   ; Looks like a comment
+  ?You must specify a number to dial
+  C-Kermit>dial \#98765421-1-212-5551212  ; Works OK
+  C-Kermit>dial =#98765421-1-212-5551212  ; This works too
+
+   When using a dialing directory, remember what happens if a name is not
+   found:
+
+  C-Kermit>dial xyzcorp
+  Lookup: "xyzcorp" - not found - dialing as given
+
+   This normally does no harm, but some modems might behave strangely
+   when given dial strings that contain certain letters. For example, a
+   certain German modem treats any dial string that contains the letter
+   "s" as a command to fetch a number from its internal list, and replies
+   OK to the ATD command, which is normally not a valid response except
+   for partial dialing. To avoid this situation, use:
+
+  lookup xyzcorp
+  if success dial
+
+  6.2. The Carrier Signal
+
+   Remember: In many C-Kermit implementations (depending on the
+   underlying operating system -- mostly Windows, OS/2, and
+   System-V-based UNIX versions, and in C-Kermit 7.0, also VMS), you
+   can't CONNECT to a modem and type the modem's dialing command (like
+   "ATDT7654321") manually, unless you first tell C-Kermit to:
+
+  SET CARRIER-WATCH OFF
+
+   This is because (in these implementations), the CONNECT command
+   requires the modem's Carrier Detect (CD) signal to be on, but the CD
+   signal doesn't come on until after dialing is complete. This
+   requirement is what allows C-Kermit to pop back to its prompt
+   automatically when the connection is hung up. See the description of
+   SET CARRIER-WATCH in "Using C-Kermit".
+
+   Similarly, if your dialed connection drops when CARRIER-WATCH is set
+   to AUTO or ON, you can't CONNECT back to the (now disconnected) screen
+   to see what might have happened unless you first SET CARRIER-WATCH
+   OFF. But sometimes not even SET CARRIER-WATCH OFF will help in this
+   situation: certain platforms (for example Unixware 2.1), once carrier
+   drops, won't let the application do i/o with the device any more. In
+   that case, if you want to use the device again, you have to CLOSE it
+   and OPEN it again. Or you can have Kermit do this for you
+   automatically by telling it to SET CLOSE-ON-DISCONNECT ON.
+
+  6.3. Dialing and Flow Control
+
+   Don't SET FLOW RTS/CTS if your modem is turned off, or if it is not
+   presenting the CTS signal. Otherwise, the serial device driver can get
+   stuck waiting for this signal to appear.
+
+   Most modern modems support RTS/CTS (if they support any hardware flow
+   control at all), but some computers use different RS-232 circuits for
+   the same purposes, e.g. DTR and CD, or DTR and CTS. In such cases, you
+   might be able to make your computer work with your modem by
+   appropriately cross-wiring the circuits in the cable connector, for
+   example the computer's DTR to the modem's RTS, and modem's CD to the
+   computer's CTS. HOWEVER, C-Kermit does not know you have done this. So
+   if you have (say) SET FLOW DTR/CD, C-Kermit will make no attempt to
+   tell the modem to use RTS/CTS. You probably did this yourself when you
+   configured the modem.
+
+  6.4. The Dial Timeout
+
+   If it takes your call longer to be completed than the timeout interval
+   that C-Kermit calculates, you can use the SET DIAL TIMEOUT command to
+   override C-Kermit's value. But beware: the modem has its own timeout
+   for completing the call. If it is a Hayes-like modem, C-Kermit adjusts
+   the modem's value too by setting register S7. But the maximum value
+   for S7 might be smaller than the time you need! In that case, C-Kermit
+   sets S7 to 0, 255, or other (modem-specific) value to signify "no
+   timeout". If Kermit attempts to set register S7 to a value higher than
+   your modem's maximum, the modem will say "ERROR" and you will get a
+   "Failure to initialize modem" error. In that case, use SET DIAL
+   TIMEOUT to override C-Kermit's calculation of the timeout value with
+   the highest value that is legal for your modem, e.g. 60.
+
+  6.5. Escape Sequence Guard Time
+
+   A "TIES" (Time-Independent Escape Sequence) modem does not require any
+   guard time around its escape sequence. The following text:
+
+  +++ATH0
+
+   if sent through a TIES modem, for example because you were uploading
+   this file through it, could pop the modem back into command mode and
+   make it hang up the connection. Later versions of the Telebit T1600
+   and T3000 (version LA3.01E firmware and later), and all WorldBlazers,
+   use TIES.
+
+   Although the probability of "+++" appearing in a Kermit packet is
+   markedly lower than with most other protocols (see the [54]File
+   Transfer section below), it can still happen under certain
+   circumstances. It can also happen when using C-Kermit's TRANSMIT
+   command. If you are using a Telebit TIES modem, you can change the
+   modem's escape sequence to an otherwise little-used control character
+   such as Ctrl-_ (Control-Underscore):
+
+  AT S2=31
+
+   A sequence of three consecutive Ctrl-_ characters will not appear in a
+   Kermit packet unless you go to extraordinary lengths to defeat more
+   than a few of Kermit's built-in safety mechanisms. And if you do this,
+   then you should also turn off the modem's escape-sequence recognition
+   altogether:
+
+  AT S48=0 S2=255
+
+   But when escape sequence recognition is turned off, "modem hangup"
+   (<pause>+++<pause>ATH0<CR>) will not work, so you should also SET
+   MODEM HANGUP RS232-SIGNAL (rather then MODEM-COMMAND).
+
+  6.6. Adaptive Dialing
+
+   Some modems have a feature called adaptive dialing. When they are told
+   to dial a number using Tone dialing, they check to make sure that
+   dialtone has gone away after dialing the first digit. If it has not,
+   the modem assumes the phone line does not accept Tone dialing and so
+   switches to Pulse. When dialing out from a PBX, there is almost always
+   a secondary dialtone. Typically you take the phone off-hook, get the
+   PBX dialtone, dial "9" to get an outside line, and then get the phone
+   company's dialtone. In a situation like this, you need to tell the
+   modem to expect the secondary dialtone. On Hayes and compatible
+   modems, this is done by putting a "W" in the dial string at the
+   appropriate place. For example, to dial 9 for an outside line, and
+   then 7654321, use ATDT9W7654321:
+
+  SET PBX-OUTSIDE-PREFIX 9W
+
+   (replace "9" with whatever your PBX's outside-line prefix is).
+
+  6.7. The Busy Signal
+
+   Some phone companies are eliminating the busy signal. Instead, they
+   issue a voice message such as "press 1 to automatically redial until
+   the number answers, or...". Obviously this is a disaster for modem
+   calls. If your service has this feature, there's nothing Kermit can do
+   about it. Your modem will respond with NO CARRIER (after a long time)
+   rather than BUSY (immediately), and Kermit will declare the call a
+   failure, rather than trying to redial the same number.
+
+  6.8. Hanging Up
+
+   There are two ways to hang up a modem: by turning off the serial
+   port's DTR signal (SET MODEM HANGUP-METHOD RS232-SIGNAL) or sending
+   the modem its escape sequence followed by its hangup command (SET
+   MODEM HANGUP-METHOD MODEM-COMMAND). If one doesn't work, try the
+   other. If the automatic hangup performed at the beginning of a DIAL
+   command causes trouble, then SET DIAL HANGUP OFF.
+
+   The HANGUP command has no effect when C-Kermit is in remote mode. This
+   is on purpose. If C-Kermit could hang up its own controlling terminal,
+   this would (a) most likely leave behind zombie processes, and (b) pose
+   a security risk.
+
+   If you DIAL a modem, disconnect, then SET HOST or TELNET, and then
+   HANGUP, Kermit sends the modem's hangup command, such as "+++ATHO".
+   There is no good way to avoid this, because this case can't reliably
+   be distinguished from the case in which the user does SET HOST
+   terminal-server, SET MODEM TYPE name, DIAL. In both cases we have a
+   valid modem type selected and we have a network connection. If you
+   want to DIAL and then later make a regular network connection, you
+   will have to SET MODEM TYPE NONE or SET DIAL HANGUP OFF to avoid this
+   phenomenon.
+    ________________________________________________________________________
+
+  7. TERMINAL SERVERS
+
+   [ [55]Top ] [ [56]Contents ] [ [57]Next ] [ [58]Previous ]
+
+   Watch out for terminal server's escape character -- usually a control
+   character such as Ctrl-Circumflex (Ctrl-^). Don't unprefix it in
+   Kermit!
+
+   Ciscos -- must often be told to "terminal download"... Cisco ASM
+   models don't have hardware flow control in both directions.
+
+   Many terminal servers only give you a 7-bit connection, so if you
+   can't make it 8-bit, tell Kermit to "set parity space".
+
+   The following story, regarding trouble transferring 8-bit files
+   through a reverse terminal server, was contributed by an Annex
+   terminal server user:
+
+     Using C-Kermit on an HP 9000 712/80 running the HP-UX 10.0
+     operating system. The HP was connected to a Xylogics Annex
+     MICRO-ELS-UX R7.1 8 port terminal server via ethernet. On the
+     second port of the terminal server is an AT&T Paradyne 3810 modem,
+     which is connected to a telephone line. There is a program which
+     runs on the HP to establish a Telnet connection between a serial
+     line on the Annex and a character special file on the HP (/dev
+     file). This is an Annex specific program called rtelnet (reverse
+     telnet) and is provided with the terminal server software. The
+     rtelnet utility runs on top of the pseudo-terminal facility
+     provided by UNIX. It creates host-originiated connections to
+     devices attached ot Annex serial ports. There are several command
+     line arguments to be specified with this program: the IP address of
+     the terminal server, the number of the port to attach to, and the
+     name of the pseudo-device to create. In addition to these there are
+     options to tell rtelnet how to operate on the connect: -b requests
+     negotiation for Telnet binary mode, -d turns on socket-leve
+     debugging, -f enables "connect on the fly" mode, -r removes the
+     device-name if it already exists, etc. The most important of these
+     to be specified when using 8 data bits and no parity, as we found
+     out, was the -t option. This creates a transparent TCP connection
+     to the terminal server. Again, what we assumed to be happening was
+     that the rtelnet program encountered a character sequence special
+     to itself and then "eating" those kermit packets. I think this is
+     all of the information I can give you on the configuration, short
+     of the values associated with the port on the terminal server.
+
+   How to DIAL from a TCP/IP reverse terminal server (modem server):
+
+    1. (only if necessary) SET TELNET ECHO REMOTE
+    2. SET HOST terminal-server-ip-name-or-address [ port ]
+    3. SET MODEM TYPE modem-type
+    4. (only if necessary) SET DIAL HANGUP OFF
+    5. (for troubleshooting) SET DIAL DISPLAY ON
+    6. DIAL phone-number
+
+   The order is important: SET HOST before SET MODEM TYPE. Since this is
+   a Telnet connection, serial-port related commands such as SET SPEED,
+   SET STOP-BITS, HANGUP (when MODEM HANGUP-METHOD is RS232), etc, have
+   no effect. However, in C-Kermit 8.0, if the modem server supports
+   [59]RFC-2217 Telnet Com-Port Control protocol, these commands do
+   indeed take effect at the server's serial port.
+    ________________________________________________________________________
+
+  8. TERMINAL EMULATION
+
+   [ [60]Top ] [ [61]Contents ] [ [62]Next ] [ [63]Previous ]
+
+   Except for the Windows, OS/2, and Macintosh versions, C-Kermit does
+   not emulate any kind of terminal. Rather, it acts as a
+   "semitransparent pipe", passing the characters you type during a
+   CONNECT session to the remote host, and sending the characters
+   received from the remote host to your screen. Whatever is controlling
+   your keyboard and screen provides the specific terminal emulation: a
+   real terminal, a PC running a terminal emulator, etc, or (in the case
+   of a self-contained workstation) your console driver, a terminal
+   window, xterm, etc.
+
+   Kermit is semitrantsparent rather than fully transparent in the
+   following ways:
+
+     * During a TELNET ("set host") session, C-Kermit itself executes the
+       TELNET protocol and performs TELNET negotiations. (But it does not
+       perform TN3270 protocol or any other type of 3270 terminal
+       emulation.)
+     * If you have changed your keyboard mapping using SET KEY, C-Kermit
+       replaces the characters you type with the characters or strings
+       they are mapped to.
+     * If you SET your TERMINAL CHARACTER-SET to anything but
+       TRANSPARENT, C-Kermit translates your keystrokes (after applying
+       any SET KEY definitions) before transmitting them, and translates
+       received characters before showing them on your screen.
+     * If your remote and/or local TERMINAL CHARACTER-SET is an ISO 646
+       7-bit national character set, such as German, French, Italian,
+       Swedish, etc, or Short KOI used for Cyrillic, C-Kermit's CONNECT
+       command automatically skips over ANSI escape sequences to avoid
+       translating their characters. Only ANSI/ISO standard
+       (VT100/200/300-like) 7-bit escape sequence formats are supported
+       for this purpose, no proprietary schemes like H-P, Televideo,
+       Tektronix, etc.
+     * If your version of C-Kermit includes SET TERMINAL APC command,
+       then C-Kermit's CONNECT command will handle APC escape sequences
+       if TERMINAL APC is not set to OFF (which is the default).
+
+   You can make C-Kermit fully transparent by starting it with the -0
+   (dash zero) command-line option.
+
+   If you are running C-Kermit under a console driver, or in a terminal
+   window, that emulates the VT100, and use C-Kermit to log in to a VMS
+   system, the console driver or terminal window (not Kermit) is supposed
+   to reply to the "what are you?" query (ESC Z) from the VAX. If it
+   doesn't, and you can't make it do so, then you can (a) live with the
+   "unknown terminal" problem; (b) tell VMS to SET TERMINAL/DEVICE=VT100;
+   (c) program a key using SET KEY to send the appropriate sequence and
+   then punch the key at the right time; or (d) use the VMSLOGIN macro
+   that is defined in CKERMIT.INI to do this for you automatically.
+
+   SET SESSION-LOG { TEXT, BINARY }, which is effective in UNIX and
+   AOS/VS but not other C-Kermit versions, removes CR, DEL, NUL, XON, and
+   XOFF characters (Using C-Kermit neglects to mention that XON and XOFF
+   are removed). The TEXT-mode setting is ineffective during SCRIPT
+   command execution, as well as on X.25 connections.
+    ________________________________________________________________________
+
+  9. KEY MAPPING
+
+   [ [64]Top ] [ [65]Contents ] [ [66]Next ] [ [67]Previous ]
+
+   Except in the terminal-emulating versions, C-Kermit's key mapping
+   facilities are limited to normal "ASCII" keys, and cannot be used with
+   function keys, arrow keys, arcane key combinations, etc. Since
+   C-Kermit runs on such a wide variety of hardware platforms (including,
+   for example, more than 360 different UNIX platforms), it is not
+   possible for C-Kermit to support every conceivable keyboard under
+   every release of every UNIX (or VMS, or ...) product on every
+   different kind of computer possibly under all manner of different
+   console drivers, even if it had the means to do so.
+
+   In technical terms, C-Kermit uses the read() function to read
+   keystrokes, and read() returns a single byte (value 0 through 255).
+   C-Kermit's SET KEY function applies to these single-byte codes.
+   "Extended function" keys, such as F-keys, arrow keys, etc, usually
+   return either a 2-byte "scan code" or else a character string (such as
+   an escape sequence like "<ESC> O p"). In both cases, C-Kermit has no
+   way to tell the difference between such multibyte key values, and the
+   corresponding series of single-byte key values. This could only be
+   done by accessing the keyboard at a much lower level in a highly
+   platform-dependent manner, probably requiring tens of thousands of
+   lines of code to support even a sampling of the most popular
+   workstation / OS combinations.
+
+   However, most workstation console drivers (terminal emulation windows,
+   etc) include their own key-mapping facility. For example in AIX, the
+   AIXterm program (in whose window you would run C-Kermit) allows
+   rebinding of the F1-F12 keys to arbitrary strings. The same is true of
+   Xterm and DECterm windows, etc. Consult the technical documentation
+   for your workstation or emulator. See sample Xterm (Xmodmap) mappings
+   in the [68]Unix C-Kermit Hints and Tips document.
+
+   The SET KEY command (except in Kermit 95) does not allow a key
+   definition to be (or contain) the NUL (\0) character.
+    ________________________________________________________________________
+
+  10. FILE TRANSFER
+
+   [ [69]Top ] [ [70]Contents ] [ [71]Next ] [ [72]Previous ]
+
+   C-Kermit 7.0 is the first release of C-Kermit to use fast (rather than
+   robust and therefore slow) protocol defaults: long packets, sliding
+   windows, control-character unprefixing, and streaming where possible.
+   This makes most transfers (partner willing) dramatically faster "out
+   of the box" but might break some combinations that worked before. If
+   transfers with C-Kermit 7.0 or later fail where transfers worked with
+   earlier C-Kermit versions, try the following (one at a time, in this
+   order):
+
+    1. SET PREFIXING ALL: Disables control-character unprefixing.
+    2. SET STREAMING OFF: Disables streaming.
+    3. CAUTIOUS: Selects medium but cautious protocol settings.
+    4. ROBUST: this command reverts to the most conservative protocol
+       settings.
+
+   Execution of multiple file transfers by C-Kermit from a command file
+   when in remote mode might exhibit long delays between each transfer.
+   To avoid this, just include the command "SET DELAY 0" in your command
+   file before any of the file-transfer commands.
+
+   File transfer failures can occur for all sorts of reasons, most of
+   them listed in Chapter 10 of [73]Using C-Kermit. The following
+   sections touch on some that aren't.
+
+   The [74]C-Kermit 7.0 Release Notes document SEND /COMMAND as taking an
+   argument, but it doesn't. Instead of SEND /COMMAND:{some command},
+   use:
+
+SEND /COMMAND [ other switches such as /AS-NAME: ] command [ arguments... ]
+
+  10.1. Laptops
+
+   Watch out for laptops and their assorted power-saver features; for
+   example, a built-in modem's "auto timeout delay" hanging up the
+   connection in the middle of a file transfer. Most modems, even if they
+   have this feature, do not have it enabled by default. But if you
+   experience otherwise inexplicable disconnections in the midst of your
+   Kermit sessions, check the modem manual for such things as "idle
+   timeout", "auto timeout", etc, and add the command to disable this
+   feature to Kermit's init string for this modem.
+
+  10.2. NFS
+
+   If uploading a large file to an NFS-mounted disk fails (or is
+   painfully slow), try uploading it to a local disk (e.g. /tmp on Unix)
+   and then copying to the NFS disk later.
+
+  10.3. Modems
+
+   If you are dialing out and find that downloads work but uploads don't,
+   try again with a lower serial-port speed. Case in point: dialing out
+   on a certain PC from Linux at 115200 bps using a USR Courier 56K
+   "V.Everything" external modem and RTS/CTS flow control. Downloads
+   worked flawlessly, uploads stopped dead after the first few packets
+   were sent. The modem lights showed constant retraining (ARQ light
+   blinks slowly), and the CTS light was off 95% of the time, allowing
+   nothing to get through. Reducing the serial port speed to 57600 bps
+   made the problems go away. Evidently the PC in question has a very
+   fast serial port, since dialing the same modem with a different PC at
+   115200 bps works without incident.
+
+  10.4. TCP/IP Connections
+
+   If you have trouble transferring files over a TCP/IP connection, tell
+   Kermit to SET PARITY SPACE and try again. If that doesn't work, also
+   try a shorter packet length or smaller window size (to compensate for
+   certain well-known broken Telnet servers), and/or SET RELIABLE OFF.
+
+  10.5. Multihop Connections
+
+   If you have a multihop connection, with the interior nodes in CONNECT
+   mode (Kermit, Telnet, Rlogin, or any other), you can expect (a) file
+   transfer to be slower, and (b) the connection to be less transparent
+   (to control characters, perhaps to the 8th bit) than a more direct
+   connection. C-Kermit 7.0 and later have a "-0" (dash-zero)
+   command-line option to make it 100% transparent in cases where it is
+   to be used in the middle.
+
+  10.6. Recovery
+
+   The recovery feature (RESEND command) that was added in version
+   5A(190) works only for binary-mode transfers. In order for this
+   feature to be useful at all, the default for SET FILE INCOMPLETE was
+   changed from DISCARD to KEEP. Otherwise an interrupted transfer would
+   leave no partial file behind unless you had remembered to change the
+   default. But now you have to pay closer attention to Kermit's messages
+   to know whether a transfer succeeded or failed -- previously, if it
+   failed, the file would not show up on the receiving end at all; in
+   5A(190) and later, you'll get a partial file which could easily be
+   mistaken for the complete file unless you change the default back to
+   DISCARD or read the screen messages, or keep a transaction log.
+
+  10.7. Filename Collisions
+
+   SET FILE COLLISION BACKUP is the default. This means:
+
+     * If you send the same file lots of times, there will be many backup
+       files. There is no automatic mechanism within Kermit to delete
+       them, no notion of a "version retention count", etc, but you can
+       use the PURGE command to clean them up.
+     * If a file arrives that has the same name as a directory, the file
+       transfer fails because Kermit will not rename a directory. Send
+       the file with another name, or use SET FILE COLLISION RENAME.
+     * If the directory lacks write permission, the file transfer fails
+       even if you have write access to the file that is being backed up;
+       in that case, switch to SET FILE COLLISION OVERWRITE or APPEND, or
+       send to a different directory.
+
+   SET FILE COLLISION UPDATE depends on the date/time stamp in the
+   attribute packet. However, this is recorded in local time, not
+   Universal Time (GMT), and there is no indication of time zone. The
+   time is expressed to the precision of 1 second, but some file systems
+   do not record with this precision -- for example, MS-DOS records the
+   file date/time only to the nearest 2 seconds. This might cause update
+   operations to send more files than necessary.
+
+   (This paragraph does NOT apply to UNIX, where, as of C-Kermit 7.0,
+   C-Kermit pipes incoming mail and print material directly the mail or
+   print program): When C-Kermit is receiving files from another Kermit
+   program that has been given the MAIL or REMOTE PRINT command, C-Kermit
+   follows the current filename collision action. This can be
+   disconcerting if the action was (for example) BACKUP, because the
+   existing file will be renamed, and the new file will be mailed (or
+   printed) and then deleted. Kermit cannot temporarily change to RENAME
+   because the file collision action occurs when the filename packet is
+   received, and the PRINT or MAIL disposition only comes later, in the
+   Attribute packet.
+
+   Watch out for SET FILE COLLISION RENAME, especially when used in
+   conjunction with recovery. Recall that this option (which is NOT the
+   default) renames the incoming file if a file already exists with the
+   same name (the default is to rename the previously existing file, and
+   store the incoming file with its own name). It is strongly recommended
+   that you do not use SET FILE COLLISION RENAME if you ever intend to
+   use the recovery feature:
+
+     * When the file is first received by C-Kermit, its name is changed
+       if another file already has the same name. When you RESEND the
+       same file after a failure, C-Kermit will probably try to append
+       the re-sent portion to the wrong file.
+     * Assuming that you get RESEND to work with FILE COLLISION RENAME,
+       C-Kermit, when receiving the remainder of the file during a RESEND
+       operation, will report back the wrong name. Nothing can be done
+       about this because the name is reported back before the receiving
+       Kermit program finds out that it is a recovery operation.
+
+   Also watch out for DISABLE DELETE, since this implicitly sets FILE
+   COLLISION to RENAME. And note tht DELETE is DISABLEd automatically any
+   time you Kermit is in local mode (i.e. it makes a connection). Also
+   note that for purposes of DISABLE and ENABLE, "set host *" connections
+   do not count as local mode even though, strictly speaking, they are.
+
+  10.8. DOS Pathnames
+
+   When referring to foreign MS-DOS, Windows, Atari ST, OS/2, or other
+   file specifications that contain backslash characters in a C-Kermit
+   command, you might have to double each backslash, for example:
+
+  C-Kermit>get c:\\directory\\foo.txt
+
+   This is because backslash is used in C-Kermit commands for introducing
+   special character codes, variables, functions, etc.
+
+  10.9. Cancellation
+
+   If attempting to cancel local-mode file reception at a very early
+   stage (i.e. before data packets are exchanged) with X or Z does not
+   work, use E or Ctrl-C instead, or wait until the first data packets
+   are sent.
+
+   If you cancel a transfer that is underway using X or Z, and a lot of
+   window slots are in use, it might take a while for the cancellation to
+   take effect, especially if you do this on the receiving end; that's
+   because a lot of packets might already be on their way to you. In that
+   case, just be patient and let Kermit "drain" them.
+
+   If C-Kermit is sending a file, remote-mode packet-mode breakout (three
+   consecutive Ctrl-C's by default) is not effective until after C-Kermit
+   sends its first packet. If C-Kermit is receiving a file or is in
+   server mode, it is effective right away. In the former case, the SET
+   DELAY value determines the earliest time at which you can break out of
+   packet mode.
+
+  10.10. Partner Peculiarities
+
+   When one or both partners is on an SCO operating system such as OSR5,
+   you might issue the command:
+
+mapchan -n
+
+   to disable character-set conversion by the terminal driver. Similarly
+   for AIX:
+
+setmaps -t NOMAP
+
+   When using C-Kermit to transfer files with the HP48SX calculator, you
+   must SET FLOW NONE. The HP48SX does not support flow control, and
+   evidently also becomes confused if you attempt to use it. You might
+   also need to use SET SEND PAUSE 100 (or other number). For greater
+   detail about transferring files the the HP-48, see:
+
+  [75]http://www.columbia.edu/kermit/hp48.html
+
+   Some communication programs have errors in their implementation of
+   Kermit attribute packets. If you get an error message from your
+   communication program like "Attribute error", tell C-Kermit to SET
+   ATTRIBUTES OFF. Better yet, switch to a real Kermit program.
+
+   Some communication software claims to implement Kermit sliding
+   windows, but does so incorrectly. If sliding window transfers fail,
+   set C-Kermit's window size to the smallest one that works, for
+   example, SET WINDOW 1.
+
+   For lots more detail about how to cope with defective Kermit partners,
+   see:
+
+     * [76]Coping with Faulty Kermit Implementations (C-Kermit 7.0 and
+       later).
+     * [77]Coping with Broken Kermit Partners (C-Kermit 8.0 and later).
+
+   The UNIX version of C-Kermit discards carriage returns when receiving
+   files in text mode. Thus, "bare" carriage returns (sometimes used to
+   achieve overstriking) are lost.
+    ________________________________________________________________________
+
+  11. SCRIPT PROGRAMMING
+
+   [ [78]Top ] [ [79]Contents ] [ [80]Previous ]
+
+  11.1. Comments Versus the SCRIPT Command
+
+   Remember that ";" and "#" introduce comments when (a) they are the
+   first character on the line, or (b) they are preceded by at least one
+   blank or tab within a line. Thus constructions like:
+
+  INPUT 5 ;
+  SCRIPT ~0 #--#--#
+
+   must be coded using backslash notation to keep the data from being
+   ignored:
+
+  INPUT 5 \59                   ; 59 is the decimal ASCII code for ";"
+  SCRIPT ~0 \35--#--#           ; 43 is the decimal ASCII code for "#"
+
+   or, more simply:
+
+  INPUT 5 \;                    ; Just quote the semicolon
+  SCRIPT ~0 \#--#--#            ; Just quote the "#"
+    ________________________________________________________________________
+
+  11.2. Alphabetic Case and the INPUT Command
+
+   INPUT and MINPUT caseless string comparisons do not work for non-ASCII
+   (international) characters. Workaround: SET INPUT CASE OBSERVE. Even
+   then, the "lexically less than" and "lexically greater than"
+   operations (IF LLT, IF LGT) probably won't work as expected. The same
+   is true for the case-conversion functions \Flower() and \Fupper().
+   C-Kermit does not know the collating sequence for different character
+   sets and languages. (On the other hand, it might work depending on
+   such items as how Kermit was linked, whether your operating supports
+   "locales", etc)
+    ________________________________________________________________________
+
+  11.3. NUL (0) Characters in C-Kermit Commands
+
+   You can't include a NUL character (\0) in C-Kermit command text
+   without terminating the character string in which it appears. For
+   example:
+
+  echo In these brackets [\0] is a NUL
+
+   will echo "In these brackets [". This applies to ECHO, INPUT, OUTPUT,
+   and all other commands (but you can represent NUL by "\N" in an OUTPUT
+   string). This is because C-language strings are terminated internally
+   by the NUL character, and it allows all of C-Kermit's string
+   comparison and manipulation functions to work in the normal "C" way.
+
+   To illustrate:
+
+  INPUT 5 \0
+
+   is equivalent to:
+
+  INPUT 5
+
+   and:
+
+  INPUT 5 ABC\0DEF
+
+   is equivalent to:
+
+  INPUT 5 ABC
+
+   INPUT operations discard and ignore NUL characters that arrive from
+   the communication device, meaning that they do not figure into
+   matching operations (e.g. A<NUL>B matches AB); they are not deposited
+   in the INPUT buffer (\v(input)); and they are not counted in
+   \v(incount), with two exceptions:
+
+    1. An arriving NUL character restarts the INPUT SILENCE timer.
+    2. An arriving NUL character terminates the INPUT command with the
+       SUCCESS condition if the INPUT command was given an empty search
+       string. In this case \v(incount) is set to 1.
+
+   Also, the \v(inchar) variable is null (completely empty) if the last
+   INPUT character was NUL. That is, there is no way to tell only by
+   looking at \v(inchar) the difference between a NUL that was INPUT and
+   no INPUT at all. If the INPUT command succeeded but \v(inchar) is
+   empty, then a NUL character was input. Also, \v(incount) will be set
+   to 1.
+
+   Here's a sample script fragment to read characters, possibly including
+   NUL, from the communication connection and write them to a file:
+
+  while true {
+      input 1                      ; read one byte
+      if fail break                ; timed out or connection closed
+      fwrite /char \%c \v(inchar)  ; record the byte
+  }
+
+   This works because when \v(inchar) is NUL, that's equivalent to FWRITE
+   /CHAR having no text argument at all, in which case it writes a NUL
+   character.
+
+   \v(incount) and \v(inchar) are NOT affected by the CLEAR command.
+    ________________________________________________________________________
+
+  11.4. \ffiles() and \fnextfile() Peculiarities
+
+   The following script program:
+
+  for \%i 1 \ffiles(oofa.*) 1 {
+      send \fnextfile()
+  }
+
+   did not work as expected in C-Kermit 6.0 and earlier but does work in
+   C-Kermit 7.0 and later.
+    ________________________________________________________________________
+
+  11.5. Commands That Have Only Local Effect
+
+   Certain settings are local to each command level, meaning that
+   subordinate command levels (macros or command files) can change them
+   without affecting their values at higher command levels. When a new
+   command level is invoked, the value is inherited from the previous
+   level. These settings are:
+
+  CASE
+  COUNT and \v(count)
+  INPUT CASE
+  INPUT TIMEOUT
+  MACRO ERROR
+  QUIET
+  TAKE ERROR
+
+   This arrangement allows CASE, TIMEOUT, and ERROR settings, which are
+   used to control automatic exit from a command file or macro upon
+   error, to be automatically restored when the command file or macro
+   exits.
+
+   The COUNT variable follows this rule too, which permits nested SET
+   COUNT / IF COUNT loops, as in this example in which the inner loop
+   counts down from the current COUNT value of the outer loop (try it):
+
+  DEFINE INNER WHILE COUNT { WRITE SCREEN {   Inner:}, SHOW COUNT }
+  SET COUNT 5
+  WHILE COUNT { WRITE SCREEN Outer:, SHOW COUNT, DO INNER }
+
+   Keep in mind that an inferior command level cannot manipulate the
+   COUNT value held by a higher level. For example:
+
+  DEFINE OOFA SHOW COUNT, IF COUNT GOTO LOOP
+  SET COUNT 5
+  :LOOP
+  OOFA
+  ECHO Done
+
+   results in an infinite loop; the COUNT value remains at 5 because it
+   is never decremented at the same level at which it was set.
+    ________________________________________________________________________
+
+  11.6. Literal Braces in Function Calls
+
+   Since braces are used in function calls to indicate grouping, there is
+   no way to pass literal braces to the function itself. Solution: Define
+   a variable containing the string that has braces. Example:
+
+  define \%a ab{cd
+  echo \fsubstring(\%a)
+  ab{cd
+
+   If the string is to start with a leading brace and end with a closing
+   brace, then double braces must appear around the string (which itself
+   is enclosed in braces):
+
+  define \%a {{{foo}}}
+  echo \fsubstring(\%a)
+  {foo}
+
+   This also works for any other kind of string:
+
+  define \%a {{ab{cd}}
+  echo \fsubstring(\%a)
+  ab{cd
+    ________________________________________________________________________
+
+  11.7. Defining Variables on the C-Kermit Command Line
+
+   To define variables on the C-Kermit command line, use the -C
+   command-line option with one or more DEFINE or ASSIGN commands. Note
+   that the C-Kermit command line must cope with the quoting rules of
+   your shell. Examples:
+
+  kermit -C "define \\%a foo, define phonenumber 7654321"
+
+   In this case we follow UNIX quoting rules by doubling the backslash.
+   Once C-Kermit starts, the \%a and \m(phonenumber) variables are
+   defined as indicated and can be used in the normal way.
+
+   In DOS or Windows or OS/2 the command would be:
+
+  kermit -C "define \%%a foo, define phonenumber 7654321"
+
+   Here we need to double the percent sign rather than the backslash
+   because of DOS shell quoting rules.
+    ________________________________________________________________________
+
+  11.8. Per-Character Echo Check with the OUTPUT Command
+
+   Sometimes the OUTPUT command must be used to send commands or data to
+   a device in "echoplex" mode, meaning that characters must be sent one
+   at a time, and the next character can not be sent until the echo from
+   the previous one has been received. For example, a certain PBX might
+   have this characteristic. Let's say a Kermit script is used to program
+   the PBX. If characters are sent too fast, they can be lost. It would
+   seem that the command:
+
+  SET OUTPUT PACING milliseconds
+
+   could be used to take care of this, but the pacing interval is
+   constant and must be set large enough to allow even the slowest echo
+   to finish. If the script is large (an actual example is 14,000 lines
+   long), this can cause it to take hours longer than it needs to.
+
+   Here is a macro you can use to OUTPUT a string in an Echoplex
+   environment:
+
+  define XOUTPUT {
+      local \%c \%i
+      set output pacing 0
+      for \%i 1 \flen(\%*) 1 {
+          asg \%c \fsubstr(\%*,\%i,1)
+          output \%c
+          input 2 \%c
+      }
+  }
+
+   C-Kermit 7.0 or later is required.
+
+   It sends one character at a time and then waits up to 2 seconds for
+   the character to be echoed back, but continues to the next character
+   as soon as the echo appears, so no time is wasted. You can add an IF
+   FAIL clause after the INPUT in case you want to do something special
+   about failure to detect an echo within the timeout period. Obviously
+   you can also change the 2-second limit, and adjust the script in any
+   other desired way.
+    ________________________________________________________________________
+
+  11.9. Scripted File Transfer
+
+   Sometimes a user complains that when she makes a connection by hand,
+   logs in, and transfers a file, there are no problems, but when she
+   scripts the the exact same sequence, the file transfer always fails
+   after a few packets. Here's a scenario where this can happen:
+
+    1. Upon logging in to the remote computer, it sends a "What Are You?"
+       escape sequence.
+    2. When you log in interactively, your terminal emulator sends the
+       response. This is invisible to you; you don't know it's happening.
+    3. When you script the login, and begin a file transfer immediately
+       upon logging in, the host still sends the "What Are You?"
+       sequence. Kermit's INPUT ECHO setting is ON by default, so the
+       escape sequence passes through to the terminal, and the terminal
+       sends its response. But by this time Kermit has already started
+       the file transfer.
+    4. By default, the local Kermit program examines the keyboard for
+       interruption characters between every packet. The "What Are You"
+       response is sitting in the keyboard buffer. Eventually Kermit will
+       read a character such as "c" that is a valid interruption
+       character, and the file transfer stops with "User cancelled".
+
+   The right way to handle this situation is to have your look for the
+   "What Are You?" sequence and send the response itself, as described in
+   Using C-Kermit, pp.429-431. Or you can work around it by telling the
+   local Kermit to "set input echo off" and/or "set transfer interruption
+   off".
+    ________________________________________________________________________
+
+  11.10. Other...
+
+   Escape sequences (or any strings that contain control characters)
+   can't be used as labels, GOTO targets, or SWITCH cases.
+
+   [ [81]Top ] [ [82]Contents ] [ [83]C-Kermit Home ] [ [84]C-Kermit 8.0
+   Overview ] [ [85]Kermit Home ]
+     _________________________________________________________________
+
+   C-Kermit 8.0 Unix Hints and Tips / [86]The Kermit Project /
+   [87]Columbia University / [88]kermit@columbia.edu / 10 April 2004
+
+References
+
+   1. http://www.columbia.edu/kermit/
+   2. http://www.columbia.edu/
+   3. http://www.columbia.edu/kermit/ckcbwr.html
+   4. http://www.columbia.edu/kermit/ckubwr.html
+   5. http://www.columbia.edu/kermit/k95.html
+   6. http://www.columbia.edu/kermit/ckermit.html
+   7. http://www.columbia.edu/kermit/ckututor.html
+   8. http://www.columbia.edu/kermit/ckcbwr.html#x0
+   9. http://www.columbia.edu/kermit/ckcbwr.html#x1
+  10. http://www.columbia.edu/kermit/ckcbwr.html#x2
+  11. http://www.columbia.edu/kermit/ckcbwr.html#x3
+  12. http://www.columbia.edu/kermit/ckcbwr.html#x4
+  13. http://www.columbia.edu/kermit/ckcbwr.html#x5
+  14. http://www.columbia.edu/kermit/ckcbwr.html#x6
+  15. http://www.columbia.edu/kermit/ckcbwr.html#x7
+  16. http://www.columbia.edu/kermit/ckcbwr.html#x8
+  17. http://www.columbia.edu/kermit/ckcbwr.html#x9
+  18. http://www.columbia.edu/kermit/ckcbwr.html#x10
+  19. http://www.columbia.edu/kermit/ckcbwr.html#x11
+  20. http://www.columbia.edu/kermit/ckcbwr.html#top
+  21. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  22. http://www.columbia.edu/kermit/ckcbwr.html#x2
+  23. http://www.columbia.edu/kermit/ckcbwr.html#top
+  24. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  25. http://www.columbia.edu/kermit/ckcbwr.html#x2
+  26. http://www.columbia.edu/kermit/ck60manual.html
+  27. http://www.columbia.edu/kermit/ckermit2.html
+  28. http://www.columbia.edu/kermit/ck60manual.html
+  29. http://www.columbia.edu/kermit/ckermit80.html#x5
+  30. http://www.columbia.edu/kermit/ckermit80.html
+  31. http://www.columbia.edu/kermit/ckermit80.html#x2.2
+  32. http://www.columbia.edu/kermit/ckcbwr.html#top
+  33. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  34. http://www.columbia.edu/kermit/ckcbwr.html#x3
+  35. http://www.columbia.edu/kermit/ckcbwr.html#x1
+  36. http://www.columbia.edu/kermit/ckcbwr.html#top
+  37. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  38. http://www.columbia.edu/kermit/ckcbwr.html#x4
+  39. http://www.columbia.edu/kermit/ckcbwr.html#x2
+  40. http://www.columbia.edu/kermit/ckcbwr.html#top
+  41. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  42. http://www.columbia.edu/kermit/ckcbwr.html#x5
+  43. http://www.columbia.edu/kermit/ckcbwr.html#x3
+  44. ftp://ftp.isi.edu/in-notes/rfc1122.txt
+  45. http://www.columbia.edu/kermit/ckcbwr.html#top
+  46. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  47. http://www.columbia.edu/kermit/ckcbwr.html#x6
+  48. http://www.columbia.edu/kermit/ckcbwr.html#x4
+  49. http://www.columbia.edu/kermit/ckcbwr.html#top
+  50. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  51. http://www.columbia.edu/kermit/ckcbwr.html#x7
+  52. http://www.columbia.edu/kermit/ckcbwr.html#x5
+  53. http://www.columbia.edu/kermit/ck60manual.html
+  54. http://www.columbia.edu/kermit/ckcbwr.html#x10
+  55. http://www.columbia.edu/kermit/ckcbwr.html#top
+  56. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  57. http://www.columbia.edu/kermit/ckcbwr.html#x8
+  58. http://www.columbia.edu/kermit/ckcbwr.html#x6
+  59. ftp://ftp.isi.edu/in-notes/rfc2217.txt
+  60. http://www.columbia.edu/kermit/ckcbwr.html#top
+  61. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  62. http://www.columbia.edu/kermit/ckcbwr.html#x9
+  63. http://www.columbia.edu/kermit/ckcbwr.html#x7
+  64. http://www.columbia.edu/kermit/ckcbwr.html#top
+  65. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  66. http://www.columbia.edu/kermit/ckcbwr.html#x10
+  67. http://www.columbia.edu/kermit/ckcbwr.html#x8
+  68. http://www.columbia.edu/kermit/ckubwr.html
+  69. http://www.columbia.edu/kermit/ckcbwr.html#top
+  70. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  71. http://www.columbia.edu/kermit/ckcbwr.html#x11
+  72. http://www.columbia.edu/kermit/ckcbwr.html#x9
+  73. http://www.columbia.edu/kermit/ck60manual.html
+  74. http://www.columbia.edu/kermit/ckermi70.htm
+  75. http://www.columbia.edu/kermit/hp48.html
+  76. http://www.columbia.edu/kermit/ckermit70.html#x4.22
+  77. http://www.columbia.edu/kermit/ckermit80.html#x15
+  78. http://www.columbia.edu/kermit/ckcbwr.html#top
+  79. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  80. http://www.columbia.edu/kermit/ckcbwr.html#x10
+  81. http://www.columbia.edu/kermit/ckcbwr.html#top
+  82. http://www.columbia.edu/kermit/ckcbwr.html#contents
+  83. http://www.columbia.edu/kermit/ckermit.html
+  84. http://www.columbia.edu/kermit/ck80.html
+  85. http://www.columbia.edu/kermit/index.html
+  86. http://www.columbia.edu/kermit/index.html
+  87. http://www.columbia.edu/
+  88. mailto:kermit@columbia.edu
diff --git a/ckermit-8.0.211/ckccfg.txt b/ckermit-8.0.211/ckccfg.txt
new file mode 100644
index 0000000..5870974
--- /dev/null
+++ b/ckermit-8.0.211/ckccfg.txt
@@ -0,0 +1,1766 @@
+
+                        C-Kermit Configuration Options
+
+     Frank da Cruz
+     [1]The Kermit Project
+     [2]Columbia University
+
+   As of: C-Kermit 8.0.211, 10 April 2004
+   This page last updated: Sun Apr 11 16:45:55 2004 (New York USA Time)
+
+     IF YOU ARE READING A PLAIN-TEXT version of this document, note that
+     this file is a plain-text dump of a Web page. You can visit the
+     original (and possibly more up-to-date) Web page here:
+
+  [3]http://www.columbia.edu/kermit/ckccfg.html
+
+   [ [4]C-Kermit Home ] [ [5]Kermit Home ]
+    ________________________________________________________________________
+
+  CONTENTS
+
+  1. [6]FILE TRANSFER
+  2. [7]SERIAL COMMUNICATION SPEEDS
+  3. [8]FULLSCREEN FILE TRANSFER DISPLAY
+  4. [9]CHARACTER SETS
+  5. [10]APC EXECUTION
+  6. [11]PROGRAM SIZE
+  7. [12]MODEM DIALING
+  8. [13]NETWORK SUPPORT
+  9. [14]EXCEPTION HANDLING
+ 10. [15]SECURITY FEATURES
+ 11. [16]ENABLING SELECT()
+ 12. [17]I/O REDIRECTION
+ 13. [18]FLOATING-POINT NUMBERS, TIMERS, AND ARITHMETIC
+ 14. [19]SPECIAL CONFIGURATIONS
+  I. [20]SUMMARY OF COMPILE-TIME OPTIONS
+    ________________________________________________________________________
+
+  OVERVIEW
+
+   This document describes configuration options for C-Kermit (5A and
+   later). The major topics covered include program size (and how to
+   reduce it), how to include or exclude particular features, notes on
+   serial-port, modem, and network support, and a list of C-Kermit's
+   compile-time options.
+
+   For details about your particular operating system, also see the
+   system-specific installation instructions file, such as the
+   [21]C-Kermit Installation Instructions for Unix.
+
+   [ [22]C-Kermit Home ] [ [23]Kermit Home ]
+    ________________________________________________________________________
+
+  1. FILE TRANSFER
+
+   [ [24]Top ] [ [25]Contents ] [ [26]Next ] [ [27]Previous ]
+
+   Prior to version 7.0, C-Kermit was always built with the most
+   conservative Kermit file-transfer protocol defaults on every platform:
+   no control-character prefixing, 94-byte packets, and a window size of
+   1.
+
+   Starting in version 7.0, fast settings are the default. To override
+   these at compile time, include:
+
+  -DNOFAST
+
+   in the C compiler CFLAGS. Even with the fast defaults, C-Kermit
+   automatically drops down to whatever window and packet sizes requested
+   by the other Kermit, if these are smaller, when sending files (except
+   for control-character unprefixing, which is not negotiated, and which
+   is now set to CAUTIOUS rather than NONE at startup). C-Kermit's
+   settings prevail when it is receiving.
+
+   [ [28]C-Kermit Home ] [ [29]Kermit Home ]
+    ________________________________________________________________________
+
+  2. SERIAL COMMUNICATION SPEEDS
+
+   [ [30]Top ] [ [31]Contents ] [ [32]Next ] [ [33]Previous ]
+
+   As of 6 September 1997, a new simplified mechanism for obtaining the
+   list of legal serial interface speeds is in place:
+
+     * If the symbol TTSPDLIST is defined, the system-dependent routine
+       ttspdlist() is called at program initialization to obtain the
+       list.
+     * This symbol should be defined only for C-Kermit implementations
+       that have implemented the ttspdlist() function, typically in the
+       ck?tio.c module. See [34]ckutio.c for an example.
+     * TTSPDLIST is automatically defined in [35]ckcdeb.h for UNIX. Add
+       the appropriate #ifdefs for other platforms when the corresponding
+       ttspdlist() functions are filled in.
+     * If TTSPDLIST is (or normally would be) defined, the old code
+       (described below) can still be selected by defining NOTTSPDLIST.
+
+   The ttspdlist() function can obtain the speeds in any way that works.
+   For example, based simply on #ifdef Bnnnn..#endif (in UNIX). Although
+   it might be better to actually check each speed against the currently
+   selected hardware interface before allowing it in the array, there is
+   usually no passive and/or reliable and safe way to do this, and so
+   it's better to let some speeds into the array that might not work,
+   than it is to erroneously exclude others. Speeds that don't work are
+   caught when the SET SPEED command is actually given.
+
+   Note that this scheme does not necessarily rule out split speed
+   operation, but effectively it does in C-Kermit as presently
+   constituted since there are no commands to set input and output speed
+   separately (except the special case "set speed 75/1200").
+
+   Note that some platforms, notably AIX 4.2 and 4.3, implement high
+   serial speeds transparently to the application, e.g. by mapping 50 bps
+   to 57600 bps, and so on.
+
+   That's the whole deal. When TTSPDLIST is not defined, the following
+   applies:
+
+   Speeds are defined in two places: the SET SPEED keyword list in the
+   command parser (as of this writing, in the [36]ckuus3.c source file),
+   and in the system- dependent communications i/o module, ck?tio.c,
+   functions ttsspd() (set speed) and ttgspd() (get speed). The following
+   speeds are assumed to be available in all versions:
+
+  0, 110, 300, 600, 1200, 2400, 4800, 9600
+
+   If one or more of these speeds is not supported by your system, you'll
+   need to change the source code (this has never happened so far). Other
+   speeds that are not common to all systems have Kermit-specific
+   symbols:
+
+               Symbol       Symbol
+  Speed (bps)  to enable    to disable
+       50       BPS_50       NOB_50
+       75       BPS_75       NOB_75
+       75/1200  BPS_7512     NOB_7512
+      134.5     BPS_134      NOB_134
+      150       BPS_150      NOB_150
+      200       BPS_200      NOB_200
+     1800       BPS_1800     NOB_1800
+     3600       BPS_3600     NOB_3600
+     7200       BPS_7200     NOB_7200
+    14400       BPS_14K      NOB_14K
+    19200       BPS_19K      NOB_19K
+    28800       BPS_28K      NOB_28K
+    38400       BPS_38K      NOB_38K
+    57600       BPS_57K      NOB_57K
+    76800       BPS_76K      NOB_76K
+   115200       BPS_115K     NOB_155K
+   230400       BPS_230K     NOB_230K
+   460800       BPS_460K     NOB_460K
+   921600       BPS_921K     NOB_921K
+
+   The [37]ckcdeb.h header file contains default speed configurations for
+   the many systems that C-Kermit supports. You can override these
+   defaults by (a) editing ckcdeb.h, or (b) defining the appropriate
+   enabling and/or disabling symbols on the CC command line, for example:
+
+  -DBPS_14400 -DNOB_115200
+
+   or the "make" command line, e.g.:
+
+  make blah "KFLAGS=-DBPS_14400 -DNOB_115200"
+
+   Note: some speeds have no symbols defined for them, because they have
+   never been needed: 12.5bps, 45.5bps, 20000bps, etc. These can easily
+   be added if required (but they will work only if the OS supports
+   them).
+
+   IMPORTANT: Adding one of these flags at compile time does not
+   necessarily mean that you will be able to use that speed. A particular
+   speed is usable only if your underlying operating system supports it.
+   In particular, it needs to be defined in the appropriate system header
+   file (e.g. in UNIX, cd to /usr/include and grep for B9600 in *.h and
+   sys/*.h to find the header file that contains the definitions for the
+   supported speeds), and supported by the serial device driver, and of
+   course by the physical device itself.
+
+   ALSO IMPORTANT: The list of available speeds is independent of how
+   they are set. The many UNIXes, for example, offer a wide variety of
+   APIs that are BSD-based, SYSV-based, POSIX-based, and purely made up.
+   See the ttsspd(), ttgspd(), and ttspdlist() routines in [38]ckutio.c
+   for illustrations.
+
+   The latest entries in this horserace are the tcgetspeed() and
+   ttsetspeed() routines found in UnixWare 7. Unlike other methods, they
+   accept the entire range of integers (longs really) as speed values,
+   rather than certain codes, and return an error if the number is not,
+   in fact, a legal speed for the device/driver in question. In this
+   case, there is no way to build a list of legal speeds at compile time,
+   since no Bnnnn symbols are defined (except for "depracated, legacy"
+   interfaces like ioctl()) and so the legal speed list must be
+   enumerated in the code -- see ttspdlist() in [39]ckutio.c.
+
+   [ [40]C-Kermit Home ] [ [41]Kermit Home ]
+    ________________________________________________________________________
+
+  3. FULLSCREEN FILE TRANSFER DISPLAY
+
+   [ [42]Top ] [ [43]Contents ] [ [44]Next ] [ [45]Previous ]
+
+   New to edit 180 is support for an MS-DOS-Kermit-like local-mode full
+   screen file transfer display, accomplished using the curses library,
+   or something equivalent (for example, the Screen Manager on DEC VMS).
+   To enable this feature, include the following in your CFLAGS:
+
+  -DCK_CURSES
+
+   and then change your build procedure (if necessary) to include the
+   necessary libraries. For example, in Unix these are usually "curses"
+   or "ncurses" (and more recenlty, "ncursesw" and "slang"), perhaps also
+   "termcap", "termlib", or "tinfo":
+
+  "LIBS= -lcurses -ltermcap"
+  "LIBS= -lcurses -ltermlib"
+  "LIBS= -lncurses"
+  "LIBS= -ltermlib"
+  "LIBS= -ltinfo"
+
+   "man curses" for further information, and search through the Unix
+   [46]makefile for "CK_CURSES" to see many examples, and also see the
+   relevant sections of the [47]Unix C-Kermit Installation Instructions,
+   particularly Sections [48]4 and [49]9.2.
+
+   There might still be a complication. Some implementations of curses
+   reserve the right to alter the buffering on the output file without
+   restoring it afterwards, which can leave Kermit's command processing
+   in a mess when the prompt comes back after a fullscreen file transfer
+   display. The typical symptom is that characters you type at the prompt
+   after a local-mode file transfer (i.e. after seeing the curses
+   file-transfer display) do not echo until you press the Return (Enter)
+   key. If this happens to you, try adding
+
+  -DCK_NEWTERM
+
+   to your makefile target (see comments in screenc() in [50]ckuusx.c for
+   an explanation).
+
+   If that doesn't fix the problem, then use a bigger hammer and replace
+   -DCK_NEWTERM with:
+
+  -DNONOSETBUF
+
+   which tells Kermit to force stdout to be unbuffered so CBREAK mode can
+   work.
+
+   In SCO Xenix and SCO UNIX, there are two separate curses libraries,
+   one based on termcap and the other based on terminfo. The default
+   library, usually terminfo, is established when the development system
+   is installed. To manually select terminfo (at compile time):
+
+  compile -DM_TERMINFO and link -ltinfo
+
+   and to manually select termcap:
+
+  compile -DM_TERMCAP and link -ltcap -ltermlib
+
+   <curses.h> looks at M_TERMINFO and M_TERMCAP to decide which header
+   files to use. /usr/lib/libcurses.a is a link to either libtinfo.a or
+   libtcap.a. The C-Kermit compilation options must agree with the
+   version of the curses library that is actually installed.
+
+   NOTE: If you are doing an ANSI-C compilation and you get compile time
+   warnings like the following:
+
+  Warning: function not declared in ckuusx.c: wmove, printw, wclrtoeol,
+  wclear, wrefresh, endwin, etc...
+
+   it means that your <curses.h> file does not contain prototypes for
+   these functions. The warnings should be harmless.
+
+   New to edit 190 is the ability to refresh a messed-up full-screen
+   display, e.g. after receiving a broadcast message. This depends on the
+   curses package including the wrefresh() and clearok() functions and
+   the curscr variable. If your version has these, or has code to
+   simulate them, then add:
+
+  -DCK_WREFRESH
+
+   The curses and termcap libraries add considerable size to the program
+   image (e.g. about 20K on a SUN-4, 40K on a 386). On some small
+   systems, such as the AT&T 6300 PLUS, curses can push Kermit over the
+   edge... even though it compiles, loads, and runs correctly, its
+   increased size apparently makes it swap constantly, slowing it down to
+   a crawl, even when the curses display is not in use. Some new makefile
+   targets have been added to take care of this (e.g. sys3upcshcc), but
+   similar tricks might be necessary in other cases too.
+
+   On the curses file-transfer display, just below the "thermometer", is
+   a running display of the transfer rate, as a flat quotient of file
+   characters per elapsed seconds so far. You can change this to an
+   average that gives greater weight to recent history (0.25 *
+   instantaneous cps + 0.75 * historical cps) by adding -DCPS_WEIGHTED to
+   your CFLAGS (sorry folks, this one is not worth a SET command). You
+   can choose a second type of weighted average in which the weighting
+   smooths out progressively as the transfer progresses by adding
+   -DCPS_VINCE to -DCPS_WEIGHTED.
+
+   An alternative to curses is also available at compile time, but should
+   be selected if your version of Kermit is to be run in local mode only
+   in an ANSI terminal environment, for example on a desktop workstation
+   that has an ANSI console driver. To select this option in place of
+   curses, define the symbol MYCURSES:
+
+  -DMYCURSES
+
+   instead of CK_CURSES. The MYCURSES option uses built-in ANSI (VT100)
+   escape sequences, and depends upon your terminal or console driver to
+   interpret them correctly.
+
+   In some C-Kermit builds, we replace printf() via #define printf...
+   However, this can cause conflicts with the [n]curses header files.
+   Various hacks are required to get around this -- see [51]ckutio.c,
+   [52]ckufio.c, [53]ckuusx.c, [54]ckucmd.c, etc.
+
+   [ [55]C-Kermit Home ] [ [56]Kermit Home ]
+    ________________________________________________________________________
+
+  4. CHARACTER SETS
+
+   [ [57]Top ] [ [58]Contents ] [ [59]Next ] [ [60]Previous ]
+
+   Since version 5A, C-Kermit has included support for conversion of
+   character sets for Western European languages (i.e. languages that
+   originated in Western Europe, but are now also spoken in the Western
+   Hemisphere and other parts of the world), via ISO 8859-1 Latin
+   Alphabet 1, for Eastern European languages (ISO Latin-2), Hebrew (and
+   Yiddish), Greek, and Cyrillic-alphabet languages (ISO Latin/Cyrillic).
+   Many file (local) character sets are supported: ISO 646 7-bit national
+   sets, IBM code pages, Apple, DEC, DG, NeXT, etc.
+
+   To build Kermit with no character-set translation at all, include
+   -DNOCSETS in the CFLAGS. To build with no Latin-2, add -DNOLATIN2. To
+   build with no Cyrillic, add -DNOCYRIL. To omit Hebrew, add -DNOHEBREW.
+   If -DNOCSETS is *not* included, you'll always get LATIN1. To build
+   with no KANJI include -DNOKANJI. There is presently no way to include
+   Latin-2, Cyrillic, Hebrew, or Kanji without also including Latin-1.
+
+   [61]Unicode support was added in C-Kermit 7.0, and it adds a fair
+   amount of tables and code (and this is only a "Level 1" implementation
+   -- a higher level would also require building in the entire Unicode
+   database). On a PC with RH 5.2 Linux, building C-Kermit 7.0, we get
+   the following sizes:
+
+  NOCSETS NOUNICODE NOKANJI   Before    After                  
+   [   ]    [   ]    [   ]    1329014   (Full)
+   [   ]    [   ]    [ X ]    1325686   (Unicode but no Kanji)
+   [   ]    [ X ]    [   ]    1158837   (All charsets except Unicode)
+   [ X ]    [ x ]    [ x ]    1090845   (NOCSETS implies the other two)
+
+   Note, by the way, that NOKANJI without NOUNICODE only removes the
+   non-Unicode Kanji sets (Shift-JIS, EUC-JP, JIS-7, etc). Kanji is still
+   representable in UCS-2 and UTF-8.
+
+   [ [62]C-Kermit Home ] [ [63]Kermit Home ]
+    ________________________________________________________________________
+
+  5. APC EXECUTION
+
+   [ [64]Top ] [ [65]Contents ] [ [66]Next ] [ [67]Previous ]
+
+   The Kermit CONNECT and INPUT commands are coded to execute Application
+   Program Command escape sequences from the host:
+
+  <ESC>_<text><ESC>\
+
+   where <text> is a C-Kermit command, or a list of C-Kermit commands
+   separated by commas, up to about 1K in length.
+
+   To date, this feature has been included in the OS/2, Windows, VMS,
+   OS-9, and Unix versions, for which the symbol:
+
+  CK_APC
+
+   is defined automatically in [68]ckuusr.h. For OS/2, APC is enabled at
+   runtime by default, for UNIX it is disabled. It is controlled by the
+   SET TERMINAL APC command. Configuring APC capability into a version
+   that gets it by default (because CK_APC is defined in [69]ckuusr.h)
+   can be overridden by including:
+
+  -DNOAPC
+
+   on the CC command line.
+
+   C-Kermit's autodownload feature depends on the APC feature, so
+   deconfiguring APC also disables autodownload (it doesn't use APC
+   escape sequences, but uses the APC switching mechanism internally).
+
+   [ [70]C-Kermit Home ] [ [71]Kermit Home ]
+    ________________________________________________________________________
+
+  6. PROGRAM SIZE
+
+   [ [72]Top ] [ [73]Contents ] [ [74]Next ] [ [75]Previous ]
+
+   SECTION CONTENTS
+
+  6.1. [76]Feature Selection
+  6.2. [77]Changing Buffer Sizes
+  6.3. [78]Other Size-Related Items
+  6.4. [79]Space/Time Tradeoffs
+
+   (Also see [80]Section 4)
+
+   Each release of C-Kermit is larger than the last. On some computers
+   (usually old ones) the size of the program prevents it from being
+   successfully linked and loaded. On some others (also usually old
+   ones), it occupies so much memory that it is constantly swapping or
+   paging. In such cases, you can reduce C-Kermit's size in various ways,
+   outlined in this section. The following options can cut down on the
+   program's size at compile time by removing features or changing the
+   size of storage areas.
+
+   If you are reading this section because all you want is a small, fast,
+   quick-to-load Kermit file-transfer application for the remote end of
+   your connection, and the remote end is Unix based, take a look at
+   G-Kermit:
+
+  [81]http://www.columbia.edu/kermit/gkermit.html
+
+  6.1. Feature Selection
+
+   Features can be added or removed by defining symbols on the CC (C
+   compiler) command line. "-D" is the normal CC directive to define a
+   symbol so, for example, "-DNODEBUG" defines the symbol NODEBUG. Some C
+   compilers might use different syntax, e.g. "-d NODEBUG" or
+   "/DEFINE=NODEBUG". For C compilers that do not accept command-line
+   definitions, you can put the corresponding #define statements in the
+   file ckcsym.h, for example:
+
+  #define NODEBUG
+
+   The following table shows the savings achieved when building C-Kermit
+   8.0 (Beta.04) with selected feature-deselection switches on an
+   Intel-based PC with Red Hat Linux 7.0 and gcc 2.96. The sizes are for
+   non-security builds. The fully configured non-security build is
+   2127408 bytes.
+
+  Option      Size    Savings Effect
+  NOICP        545330   74.4% No Interactive Command Parser (command-line only)
+  NOLOCAL     1539994   27.6% No making connections.
+  NOXFER      1551108   27.1% No file transfer.
+  IKSDONLY    1566608   26.4% Internet Kermit Server only.
+  NOCSETS     1750097   17.7% No character-set conversion.
+  NOSPL       1800293   15.4% No Script Programming Language.
+  NONET       1808575   15.0% No making network connections.
+  NOUNICODE   1834426   13.8% No Unicode character-set conversion.
+  NOHELP      1837877   13.6% No built-in help text.
+  NODEBUG     1891669   11.1% No debug log.
+  NOFRILLS    1918966    9.8% No "frills".
+  NOFTP       1972496    7.3% No FTP client.
+  NODIAL      1984488    6.7% No automatic modem dialing.
+  NOPUSH      2070184    2.7% No shell access, running external programs, etc.
+  NOIKSD      2074129    2.5% No Internet Kermit Server capability.
+  NOHTTP      2082610    2.1% No HTTP client.
+  NOFLOAT     2091332    1.7% No floating-point arithmetic.
+  NOCHANNELIO 2095978    1.5% No FOPEN/FREAD/FWRITE/FCLOSE, etc.
+  MINIDIAL    2098035    1.4% No built-in support for many kinds of modems.
+  NOSERVER    2098987    1.3% No server mode.
+  NOSEXP      2105898    1.0% No S-Expressions.
+  NOPTY       2117743    0.5% No pseudoterminal support.
+  NORLOGIN    2121089    0.3% No RLOGIN connections.
+  NOOLDMODEMS 2124038    0.2% No built-in support for old kinds of modems.
+  NOSSH       2125696    0.1% No SSH command.
+
+   And here are a few combinations
+
+   Options Size Savings Effect
+   NODEBUG NOICP NOCSETS NOLOCAL 281641 86.7% No debug log, parser,
+   character sets, or making connections.
+   NOICP NOCSETS NOLOCAL 376468 82.3% No parser, character sets, or
+   making connections.
+   NOICP NOCSETS NONET 427510 79.9% No parser, character sets, or network
+   connections.
+   NOSPL NOCSETS 1423784 33.1% No script language, or character sets.
+
+   -DNOFRILLS removes various command synonyms; the following top-level
+   commands: CLEAR, DELETE, DISABLE, ENABLE, GETOK, MAIL, RENAME, TYPE,
+   WHO; and the following REMOTE commands: KERMIT, LOGIN, LOGOUT, PRINT,
+   TYPE, WHO.
+
+  6.2. Changing Buffer Sizes
+
+   Most modern computers have so much memory that (a) there is no need to
+   scrimp and save, and (b) C-Kermit, even when fully configured, is
+   relatively small by today's standards.
+
+   Two major factors affect Kermit's size: feature selection and buffer
+   sizes. Buffer sizes affect such things as the maximum length for a
+   Kermit packet, the maximum length for a command, for a macro, for the
+   name of a macro, etc. Big buffer sizes are used when the following
+   symbol is defined:
+
+  BIGBUFOK
+
+   as it is by default for most modern platforms (Linux, AIX 4 and 5,
+   HP-UX 10 and 11, Solaris, etc) in [82]ckuusr.h. If your build does not
+   get big buffers automatically (SHOW FEATURES tells you), you can
+   include them by rebuilding with BIGBUFOK defined; e.g. in Unix:
+
+  make xxxx KFLAGS=-DBIGBUFOK
+
+   where xxxx is the makefile target. On the other hand, if you want to
+   build without big buffers when they normally would be selected, use:
+
+  make xxxx KFLAGS=-DNOBIGBUF
+
+   There are options to control Kermit's packet buffer allocations. The
+   following symbols are defined in [83]ckcker.h in such a way that you
+   can override them by redefining them in CFLAGS:
+
+  -DMAXSP=xxxx - Maximum send-packet length.
+  -DMAXRP=xxxx - Maximum receive-packet length.
+  -DSBSIZ=xxxx - Total allocation for send-packet buffers.
+  -DRBSIZ=xxxx - Total allocation for receive-packet buffers.
+
+   The defaults depend on the platform.
+
+   Using dynamic allocation (-DDYNAMIC) reduces storage requirements for
+   the executable program on disk, and allows more and bigger packets at
+   runtime. This has proven safe over the years, and now most builds
+   (e.g. all Unix, VMS, Windows, and OS/2 ones) use dynamic memory
+   allocation by default. If it causes trouble, however, then omit the
+   -DDYNAMIC option from CFLAGS, or add -DNODYNAMIC.
+
+  6.3. Other Size-Related Items
+
+   To make Kermit compile and load successfully, you might have to change
+   your build procedure to:
+
+    a. Request a larger ("large" or "huge") compilation / code-generation
+       model. This is needed for 16-bit PC-based UNIX versions (most or
+       all of which fail to build C-Kermit 7.0 and later anyway). This is
+       typically done with a -M and/or -F switch (see your cc manual or
+       man page for details).
+    b. Some development systems support overlays. If the program is too
+       big to be built as is, check your loader manual ("man ld") to see
+       if an overlay feature is available. See the 2.10/2.11 BSD example
+       in the UNIX makefile. (Actually, as of version 7.0, C-Kermit is
+       too big to build, period, even with overlays, on 2.xx BSD).
+    c. Similarly, some small and/or segment-based architectures support
+       "code mapping", which is similar to overlays (PDP11-based VENIX
+       1.0, circa 1984, was an example). See the linker documentation on
+       the affected platform.
+
+   It is also possible to reduce the size of the executable program file
+   in several other ways:
+
+    a. Include the -O (optimize) compiler switch if it isn't already
+       included in your "make" entry (and if it works!). If your compiler
+       supports higher levels of optimization (e.g. -O2 or higher number,
+       -Onolimit (HP-UX), etc), try them; the greater the level of
+       optimization, the longer the compilation and more likely the
+       compiler will run out of memory. The the latter eventuality, some
+       compilers also provide command-line options to allocate more
+       memory for the optimizer, like "-Olimit number" in Ultrix.
+    b. If your platofrm supports shared libraries, change the make entry
+       to take advantage of this feature. The way to do this is, of
+       course, platform dependent; see the NeXT makefile target for an
+       example. some platforms (like Solaris) do it automatically and
+       give you no choice. But watch out: executables linked with shared
+       libraries are less portable than statically linked executables.
+    c. Strip the program image after building ("man strip" for further
+       info), or add -s to the LNKFLAGS (UNIX only). This strips the
+       program of its symbol table and relocation information.
+    d. Move character strings into a separate file. See the 2.11 BSD
+       target for an example.
+
+  6.4. Space/Time Tradeoffs
+
+   There are more than 6000 debug() statements in the program. If you
+   want to save both space (program size) and time (program execution
+   time), include -DNODEBUG in the compilation. If you want to include
+   debugging for tracking down problems, omit -DNODEBUG from the make
+   entry. But when you include debugging, you have two choices for how
+   it's done. One definition defines debug() to be a function call; this
+   is cheap in space but expensive in execution. The other defines debug
+   as "if (deblog)" and then the function call, to omit the function call
+   overhead when the debug log is not active. But this adds a lot of
+   space to the program. Both methods work, take your choice; IFDEBUG is
+   preferred if memory is not a constraint but the computer is likely to
+   be slow. The first method is the default, i.e. if nothing is done to
+   the CFLAGS or in [84]ckcdeb.h (but in some cases, e.g. VMS, it is). To
+   select the second method, include -DIFDEBUG in the compilation (and
+   don't include -DNODEBUG).
+
+   [ [85]C-Kermit Home ] [ [86]Kermit Home ]
+    ________________________________________________________________________
+
+  7. MODEM DIALING
+
+   [ [87]Top ] [ [88]Contents ] [ [89]Next ] [ [90]Previous ]
+
+   -DNODIAL removes automatic modem dialing completely, including the
+   entire [91]ckudia.c module, plus all commands that refer to dialing in
+   the various ckuus*.c modules.
+
+   -DMINIDIAL leaves the DIAL and related commands (SET/SHOW MODEM,
+   SET/SHOW DIAL) intact, but removes support for all types of modems
+   except CCITT, Hayes, Unknown, User-defined, Generic-high-speed, and
+   None (= Direct). The MINIDIAL option cuts the size of the dial module
+   approximately in half. Use this option if you have only Hayes or CCITT
+   modems and don't want to carry the baggage for the other types.
+
+   A compromise between full dialer support and MINIDIAL is obtained by
+   removing support for "old" modems -- all the strange non-Hayes
+   compatible 1200 and 2400 bps modems that C-Kermit has been carrying
+   around since 1985 or so. To remove support for these modems, add
+   -DNOOLDMODEMS to CFLAGS at compilation time.
+
+   Finally, if you keep support for old modems, you will notice that
+   their names appear on the "set modem ?" menu. That's because their
+   names are, by default, "visible". But the list is confusing to the
+   younger generation, who have only heard of modems from the
+   V.32bis-and-later era. If you want to be able to use old modems, but
+   don't want their names cluttering up menus, add this to CFLAGS:
+
+  -DM_OLD=1
+
+   [ [92]C-Kermit Home ] [ [93]Kermit Home ]
+    ________________________________________________________________________
+
+  8. NETWORK SUPPORT
+
+   [ [94]Top ] [ [95]Contents ] [ [96]Next ] [ [97]Previous ]
+
+   SECTION CONTENTS
+
+  8.1. [98]TCP/IP
+  8.2. [99]X.25
+  8.3. [100]Other Networks
+
+   C-Kermit supports not only serial-port and modem connections, but also
+   TCP/IP and X.25 network connections. Some versions support other
+   network types too like DECnet, LAT, NETBIOS, etc. If you define the
+   following symbol:
+
+  NONET
+
+   then all network support is compiled away.
+
+  8.1. TCP/IP
+
+   SUBSECTION CONTENTS
+
+  8.1.1. [101]Firewalls
+  8.1.2. [102]Compilation and Linking Problems
+  8.1.3. [103]Enabling Host Address Lists
+  8.1.4. [104]Enabling Telnet NAWS
+  8.1.5. [105]Enabling Incoming TCP/IP Connections
+  8.1.6. [106]Disabling SET TCP Options
+
+   C-Kermit's TCP/IP features require the Berkeley sockets library or
+   equivalent, generally available on any Unix system, as well as in
+   Windows 9x/NT, OS/2, VMS, AOS/VS, VOS, etc. The TCP/IP support
+   includes built-in TELNET, FTP, and HTTP protocol. To select TCP/IP
+   support, include -DTCPSOCKET in your makefile target's CFLAGS, or (in
+   VMS) the appropriate variant (e.g. -DWOLLONGONG, -DMULTINET,
+   -DEXCELAN, -DWINTCP, etc).
+
+   The VMS and/or early Unix third-party TCP/IP products are often
+   incompatible with each other, and sometimes with different versions of
+   themselves. For example, Wollongong reportedly put header files in
+   different directories for different UNIX versions:
+
+     * in.h can be in either /usr/include/sys or /user/include/netinet.
+     * telnet.h can be in either /usr/include/arpa or
+       /user/include/netinet.
+     * inet.h can be in either /usr/include/arpa or /user/include/sys.
+
+   In cases like this, use the -I cc command-line option when possible;
+   otherwise it's better to make links in the file system than it is to
+   hack up the C-Kermit source code. Suppose, for example, Kermit is
+   looking for telnet.h in /usr/include/arpa, but on your computer it is
+   in /usr/include/netinet. Do this (as root, or get the system
+   administrator to do it):
+
+  cd /usr/include/arpa
+  ln /usr/include/netinet/telnet.h telnet.h
+
+   ("man ln" for details about links.)
+
+   The network support for TCP/IP and X.25 is in the source files
+   [107]ckcnet.h, [108]ckctel.c, [109]ckctel.c, [110]ckctel.h,
+   [111]ckcftp.c, with miscellaneous SHOW commands, etc, in the various
+   ckuus*.c modules, plus code in the ck*con.c or ckucns.c (CONNECT
+   command) and several other modules to detect TELNET negotiations, etc.
+
+   Within the TCPSOCKET code, some socket-level controls are included if
+   TCPSOCKET is defined in the C-Kermit CFLAGS and SOL_SOCKET is defined
+   in in the system's TCP-related header files, such as <sys/socket.h>.
+   These are:
+
+  SET TCP KEEPALIVE
+  SET TCP LINGER
+  SET TCP RECVBUF
+  SET TCP SENDBUF
+
+   In addition, if TCP_NODELAY is defined, the following command is also
+   enabled:
+
+  SET TCP NODELAY (Nagle algorithm)
+
+   See the [112]C-Kermit user documentation for descriptions of these
+   commands.
+
+  8.1.1. Firewalls
+
+   There exist various types of firewalls, set up to separate users of an
+   internal TCP/IP network ("Intranet") from the great wide Internet, but
+   then to let selected users or services get through after all.
+
+   One firewall method is called SOCKS, in which a proxy server allows
+   users inside a firewall to access the outside world, based on a
+   permission list generally stored in a file. SOCKS is enabled in one of
+   two ways. First, the standard sockets library is modified to handle
+   the firewall, and then all the client applications are relinked (if
+   necessary, i.e. if the libraries are not dynamically loaded) with the
+   modified sockets library. The APIs are all the same, so the
+   applications do not need to be recoded or recompiled.
+
+   In the other method, the applications must be modified to call
+   replacement routines, such as Raccept() instead of accept(), Rbind()
+   instead of bind(), etc, and then linked with a separate SOCKS library.
+   This second method is accomplished (for SOCKS4) in C-Kermit by
+   including -DCK_SOCKS in your CFLAGS, and also adding:
+
+  -lsocks
+
+   to LIBS, or replacing -lsockets with -lsocks (depending on whether the
+   socks library also includes all the sockets entry points).
+
+   For SOCKS5, use -DCK_SOCKS5.
+
+   Explicit firewall support can, in general, not be a standard feature
+   or a feature that is selected at runtime, because the SOCKS library
+   tends to be different at each site -- local modifications abound.
+
+   The ideal situation occurs when firewalls are supported by the first
+   method, using dynamically linked sockets-replacement libraries; in
+   this case, all your TCP/IP client applications negotiate the firewall
+   transparently.
+
+  8.1.2. Compilation and Linking Problems
+
+   If you get a compilation error in [113]ckcnet.c, with a complaint like
+   "incompatible types in assignment", it probably has something to do
+   with the data type your system uses for the inet_addr() function,
+   which is declared (usually) in <arpa/inet.h>. Kermit uses "unsigned
+   long" unless the symbol INADDRX is defined, in which case "struct
+   inaddr" is used instead. Try adding -DINADDRX to CFLAGS in your make
+   entry, and if that fixes the problem, please send a report to
+   kermit@columbia.edu.
+
+   Compilation errors might also have to do with the data type used for
+   getsockopt() and setsockopt() option-length field. This is normally an
+   int, but sometimes it's a short, a long, or an unsigned any of those,
+   or a size_t. To fix the compilation problem, add -DSOCKOPT_T=xxx to
+   the CFLAGS in your makefile target, where xxx is the appropriate type
+   (use "man getsockopt" or grep through your system/network header files
+   to find the needed type).
+
+  8.1.3. Enabling Host Address Lists
+
+   When you give Kermit an IP host name, it calls the socket routine
+   gethostbyname() to resolve it. gethostbyname() returns a hostent
+   struct, which might or might not not include a list of addresses; if
+   it does, then if the first one fails, Kermit can try the second one,
+   and so on. However, this will only work if the symbol "h_addr" is a
+   macro defined as "h_addr_list[0]", usually in netdb.h. If it is, then
+   you can activate this feature by defining the following symbol in
+   CFLAGS:
+
+  HADDRLIST
+
+  8.1.4. Enabling Telnet NAWS
+
+   The Telnet Negotiation About Window Size (NAWS) option requires the
+   ability to find out the terminal screen's dimensions. E.g. in Unix, we
+   need something like ioctl(0, TIOCGWINSZ, ...). If your version of
+   Kermit was built with NAWS capability, SHOW VERSIONS includes CK_NAWS
+   among the compiler options. If it doesn't, you can add it by defining
+   CK_NAWS at compile time. Then, if the compiler or linker complain
+   about undefined or missing symbols, or there is no complaint but SHOW
+   TERMINAL fails to show reasonable "Rows =, Columns =" values, then
+   take a look at (or write) the appropriate ttgwsiz() routine. On the
+   other hand, if CK_NAWS is defined by default for your system (in
+   [114]ckcnet.h), but causes trouble, you can override this definition
+   by including the -DNONAWS switch on your CC command line, thus
+   disabling the NAWS feature.
+
+   This appears to be needed at least on the AT&T 3B2, where in
+   [115]ckutio.c, the routine ttgwsiz() finds that the TIOCGWINSZ symbol
+   is defined but lacks definitions for the corresponding winsize struct
+   and its members ws_col and ws_row.
+
+   The UNIX version of C-Kermit also traps SIGWINCH, so it can send a
+   NAWS to the Telnet server any time the local console terminal window
+   size changes, e.g. when you stretch it with a mouse. The
+   SIGWINCH-trapping code is enabled if SIGWINCH is defined (i.e. in
+   signal.h). If this code should cause problems, you can disable it
+   without disabling the NAWS feature altogether, by defining NOSIGWINCH
+   at compile time.
+
+  8.1.5. Enabling Incoming TCP/IP Connections
+
+   This feature lets you "set host * port" and wait for an incoming
+   connection on the given port. This feature is enabled automatically at
+   compile if TCPSOCKET is defined and SELECT is also defined. But watch
+   out, simply defining SELECT on the cc command line does not guarantee
+   successful compilation or linking (see [116]Section 11).
+
+   If you want to disable incoming TCP/IP connections, then build
+   C-Kermit with:
+
+  -DNOLISTEN
+
+  8.1.6. Disabling SET TCP Options
+
+   The main reason for this is because of header file / prototype
+   conflicts at compile time regardting get- / setsockopt(). If you can't
+   fix them (without breaking other builds), add the following in CFLAGS:
+
+  -DNOTCPOPTS
+
+  8.2. X.25
+
+   X.25 support requires (a) a Sun, (b) the SunLink product (libraries
+   and header files), and (c) an X.25 connection into your Sun. Similarly
+   (in C-Kermit 7.0 or later) Stratus VOS and IBM AIX.
+
+   In UNIX, special makefile targets sunos4x25 and sunos41x25 (for SUNOS
+   4.0 and 4.1, respectively), or aix41x25, are provided to build in this
+   feature, but they only work if conditions (a)-(c) are met. To request
+   this feature, include -DSUNX25 (or -DIBMX25) in CFLAGS.
+
+   SUNX25 (or -DIBMX25) and TCPSOCKET can be freely mixed and matched,
+   and selected by the user at runtime with the SET NETWORK TYPE command
+   or SET HOST switches.
+
+  8.3. Other Networks
+
+   Support for other networking methods -- NETBIOS, LAT, Named Pipes, etc
+   -- is included in ck*net.h and ck*net.c for implementations (such as
+   Windows or OS/2) where these methods are supported.
+
+   Provision is made in the organization of the modules, header files,
+   commands, etc, for addition of new network types such as DECnet, X.25
+   for other systems (HP-UX, VMS, etc), and so on. Send email to
+   [117]kermit@columbia.edu if you are willing and able to work on such a
+   project.
+
+   [ [118]C-Kermit Home ] [ [119]Kermit Home ]
+    ________________________________________________________________________
+
+  9. EXCEPTION HANDLING
+
+   [ [120]Top ] [ [121]Contents ] [ [122]Next ] [ [123]Previous ]
+
+   The C language setjmp/longjmp mechanism is used for handling
+   exceptions. The jump buffer is of type jmp_buf, which almost
+   everywhere is typedef'd as an array, in which case you should have no
+   trouble compiling the exception-handling code. However, if you are
+   building C-Kermit in/for an environment where jmp_buf is something
+   other than an array (e.g. a struct), then you'll have to define the
+   following symbol:
+
+  JBNOTARRAY
+
+   [ [124]C-Kermit Home ] [ [125]Kermit Home ]
+    ________________________________________________________________________
+
+  10. SECURITY FEATURES
+
+   [ [126]Top ] [ [127]Contents ] [ [128]Next ] [ [129]Previous ]
+
+   Security, in the sense of secure authentication and strong encryption,
+   can be built into versionf of C-Kermit for which the appropriate
+   libraries and header files are available (Kerberos IV, Kerberos V,
+   OpenSSL, SRP), as explained in great detail in the Kermit Security
+   Reference
+   . The following symbols govern C-Kermit's security features at build
+   time:
+
+   NO_AUTHENTICATION
+          Means do not configure any TELNET AUTHENTICATION support. It
+          implies NO_ENCRYPTION and undefines any of the auth and encrypt
+          types. It does not undefine CK_SSL even though builds with
+          CK_SSL cannot succeed without CK_AUTHENTICATION. (This will be
+          supported in a future release. It will be needed to allow
+          C-Kermit to be built only as an FTP client.)
+
+   NO_KERBEROS
+          Means do not compile in any KERBEROS support when
+          CK_AUTHENTICATION has been defined.
+
+   NO_SRP
+          Do not compile in any SRP support when CK_AUTHENTICATION has
+          been defined.
+
+   NO_SSL
+          Do not compile in any SSL/TLS support
+
+   NO_ENCRYPTION
+          Do not compile in any Telnet encryption support. It does not
+          affect the use of SSL/TLS
+
+   NOSSH
+          Do not compile in any SSH support whether internal or external
+
+   CK_AUTHENTICATION
+          Telnet AUTHENTICATION support. (Also, required if SSL/TLS
+          support is desired.) On most platforms this does not autodefine
+          any authentication mechanisms such as Kerberos V, Kerberos IV,
+          SRP, ... Those need to be defined separately.
+
+   CK_KERBEROS
+          Defined automatically when KRB4, KRB5, or KRB524 are defined.
+          Implies that some version of Kerberos is in use.
+
+   KRB4
+          Should be defined when Kerberos IV support is desired.
+
+   KRB5
+          Should be defined when Kerberos V support is desired.
+
+   KRB524
+          Should be defined if both Kerberos V and Kerberos IV are used
+          and the Kerberos IV support is provided by the MIT Kerberos IV
+          compatibility library in the current Kerberos 5 distribution.
+
+   KRB5_U2U
+          Should be defined if KRB5 is defined and Kerberos 5 User to
+          User mode is desired.
+
+   HEIMDAL
+          Should be defined if Kerberos V support is provided by HEIMDAL.
+          Support for this option is not complete in C-Kermit 8.0. Anyone
+          interested in working on this should contact kermit-support.
+
+   CK_SRP
+          Should be defined if SRP support is desired.
+
+   CK_ENCRYPTION
+          Should be defined if TELNET ENCRYPTION option support is
+          desired. This option does not define any particular encryption
+          types. That should be done by defining CK_DES or CK_CAST.
+
+   CK_DES
+          Should be defined if either DES or 3DES Telnet Encryption
+          option support is desired.
+
+   LIBDES
+          If CK_DES is defined and DES support is being provided by
+          either Eric Young's libdes.a or OpenSSL 0.9.6x or earlier, this
+          option must be defined. If it is not defined, it will be
+          assumed that DES support is provided by the MIT Kerberos IV
+          libraries.
+
+   CK_CAST
+          Should be defined if CAST Telnet Encryption option support is
+          desired
+
+   CK_SSL
+          Should be defined if SSL/TLS support (OpenSSL) is desired.
+
+   SSL_KRB5
+          If KRB5 is defined, and OpenSSL is built to support the
+          Kerberos 5 ciphers, then you should define SSL_KRB5
+
+   NOSSLKRB5
+          If you are using OpenSSL 0.9.7 or higher and do not wish to
+          build with support for Kerberos 5 TLS ciphers, this option must
+          be defined.
+
+   ZLIB
+          If you are using OpenSSL 0.9.6 or higher and it has been
+          compiled with support for ZLIB compression, this option should
+          be defined to enable Kermit to properly enable the use of
+          compression.
+
+   SSHCMD
+          Defined for C-Kermit to enable the use of external SSH clients
+          from the Kermit command language
+
+   SSHBUILTIN
+          Defined for Kermit implementations that have integrated SSH
+          support. Currently only Windows.
+
+   ANYSSH
+          Defined if either SSHCMD or SSHBUILTIN are defined.
+
+   CK_SNDLOC
+          Telnet Send Location support.
+
+   NOSNDLOC
+          Do not include Telnet Send Location support.
+
+   CK_XDISPLOC
+          Telnet X-Display Location support. Determines if the X-Display
+          location information is sent to the Telnet server either via
+          Telnet XDISPLOC or NEW-ENV options.
+
+   NOXDISPLOC
+          Do not include Telnet X-Display Location support.
+
+   CK_FORWARD_X
+          Telnet Forward X Windows Session Data option. Used to protect
+          the privacy and integrity of X Windows Sessions when secure
+          telnet sessions are in use.
+
+   NOFORWARDX
+          Do not include Telnet Forward X Windows Session Data option.
+
+   Besides the strong forms of security listed above, C-Kermit also
+   embodies various internal security features, including:
+
+   NOPUSH
+          Compiling with the NOPUSH symbol defined removes all the "shell
+          escape" features from the program, including the PUSH, RUN, and
+          SPAWN commands, the "!" and "@" command prefixes, OPEN !READ,
+          OPEN !WRITE, job control (including the SUSPEND command), the
+          REDIRECT command, shell/DCL escape from CONNECT mode, as well
+          as the server's execution of REMOTE HOST commands (and, of
+          course, the ENABLE HOST command). Add NODISPO to also prevent
+          acceptance of incoming MAIL or REMOTE PRINT files. For UNIX,
+          also be sure to read [130]Section 11 of the [131]Unix C-Kermit
+          Installation Instructions. about set[ug]id configuration.
+          Additional restrictions can be enforced when in server mode;
+          read about the DISABLE command in the user manual.
+
+   NOCCTRAP
+          Compiling with NOCCTRAP prevents the trapping of SIGINT by
+          Kermit. Thus if the user generates a SIGINT signal (e.g. by
+          typing the system's interrupt character), Kermit will exit
+          immediately, rather than returning to its prompt.
+
+   NOPUSH and NOCCTRAP together allow Kermit to be run from restricted
+   shells, preventing access to system functions.
+
+   [ [132]C-Kermit Home ] [ [133]Kermit Home ]
+    ________________________________________________________________________
+
+  11. ENABLING SELECT()
+
+   [ [134]Top ] [ [135]Contents ] [ [136]Next ] [ [137]Previous ]
+
+   Kermit works best if it can do nonblocking reads, nondestructive input
+   buffer checking, and millisecond sleeps. All of these functions can be
+   accomplished by the select() function, which, unfortunately, is not
+   universally available. Furthermore, select() is required if incoming
+   TCP/IP connections are to be supported.
+
+   select() was introduced with Berkeley UNIX, rejected by AT&T for
+   System V, but is gradually creeping in to all UNIX versions (and other
+   operating systems too) by virtue of its presence in the sockets
+   library, which is needed for TCP/IP. AT&T SVID for System V R4
+   includes select(), but that does not mean that all SVR4
+   implementations have it.
+
+   Furthermore, even when select() is available, it might work only on
+   socket file descriptors, but not on others like serial ports, pipes,
+   etc. For example, in AOS/VS and BeOS, it works only with file
+   descriptors that were created by socket() and opened by connect() or
+   accept().
+
+   Other alternatives include poll() and rdchk(). Only one of these three
+   functions should be included. The following symbols govern this:
+
+     SELECT  Use select() (BSD, or systems with sockets libraries)
+     CK_POLL Use poll()   (System V)
+     RDCHK   Use rdchk()  (SCO XENIX and UNIX)
+
+   If your system supports the select() function, but your version of
+   C-Kermit does not, try adding:
+
+  -DSELECT
+
+   to the CFLAGS, and removing -DRDCHK or -DCK_POLL if it is there. If
+   you get compilation errors, some adjustments to ck*tio.c and/or
+   ck*net.c might be needed; search for SELECT (uppercase) in these files
+   (note that there are several variations on the calling conventions for
+   select()).
+
+   Various macros and data types need to be defined in order to use
+   select(). Usually these are picked up from <types.h> or <sys/types.h>.
+   But on some systems, they are in <sys/select.h>. In that case, add the
+   following:
+
+  -DSELECT_H
+
+   to the CFLAGS to tell C-Kermit to #include <sys/select.h>. A good
+   indication that you need to do this would be if you get compile-time
+   complaints about "fd_set" or "FD_SET" not being declared or defined.
+
+   In UNIX, the use of select() vs fork() in the CONNECT command is
+   independent of the above considerations, and is governed by choosing a
+   particular makefile target.
+
+   As of C-Kermit 7.0, select() is also the preferred control mechanism
+   for the CONNECT command. Unfortunately, the structures used by the
+   original UNIX CONNECT command, based on fork(), and those used by
+   select(), are so different, it was not practical to implement them
+   both in one module. So the select()-based CONNECT command module for
+   UNIX is [138]ckucns.c, and the fork-based one remains [139]ckucon.c.
+   To choose the fork-based one, which is more portable (but slower and
+   more fragile), use "wermit" as the make target. To choose the
+   select-based one, use "xermit". Only do this if you can verify that
+   the CONNECT command works on serial connections and PIPE connections
+   as well as TCP connections.
+
+     The select()-based Unix CONNECT module, ckucns.c, must be used if
+     encryption is to be done, since the fork() version (ckucon.c) loses
+     its ability to share vital state information between the two forks.
+     Also note that the select() version is superior in many other ways
+     too. For example, it recovers better from exterior killing, forced
+     disconnections, etc, plus it goes faster.
+
+   SHOW VERSIONS tells whether the CONNECT module uses fork() or
+   select().
+
+   C-Kermit 8.0 adds learned script capability, which depends on
+   select(). All the "wermit" based targets (as opposed to "xermit") had
+   NOLEARN added to them. Whenever changing a target over from wermit to
+   xermit, also remember to remove NOLEARN.
+
+   [ [140]C-Kermit Home ] [ [141]Kermit Home ]
+    ________________________________________________________________________
+
+  12. I/O REDIRECTION
+
+   [ [142]Top ] [ [143]Contents ] [ [144]Next ] [ [145]Previous ]
+
+   The REDIRECT command allows a local program to be run with its i/o
+   redirected over the communications connection. Your version of
+   C-Kermit has a REDIRECT command if it was built with the following
+   CFLAG:
+
+  -DCK_REDIR
+
+   This, in turn, is possible only if the underlying API is there. In the
+   case of UNIX this is just the wait() system call, so all UNIX versions
+   get this feature as of 6.0.192 (earlier versions needed a <sys/wait.h>
+   header file defining the symbols WIFEXITED and WEXITSTATUS).
+
+   As of version 7.0, file transfer can be done using pipes and filters.
+   To enable this feature, #define PIPESEND (and fill in the code). To
+   disable on systems where it is normally enabled, define NOPIPESEND.
+   This feature is, of course, also disabled by building with NOPUSH (or
+   giving the "nopush" command at runtime).
+
+   C-Kermit 7.0 also adds the PIPE and SET HOST /COMMAND commands, which
+   provide another form of redirection. This feature is selected with
+   -DNETCMD. CK_RDIR must also be defined, since the same mechanisms are
+   used internally.
+
+   [ [146]C-Kermit Home ] [ [147]Kermit Home ]
+    ________________________________________________________________________
+
+  13. FLOATING-POINT NUMBERS, TIMERS, AND ARITHMETIC
+
+   [ [148]Top ] [ [149]Contents ] [ [150]Next ] [ [151]Previous ]
+
+   Floating-point support was added in C-Kermit 7.0.
+
+   Floating-point numbers are enabled internally, at least for use in
+   high-precision file-transfer timers and statistics, unless the
+   following symbol is defined at compile time:
+
+  -DNOFLOAT
+
+   This might be necessary on old PCs that do not have built-in
+   floating-point hardware.
+
+   When NOFLOAT is not defined, the following symbol tells which
+   floating-point type to use:
+
+  -DCKFLOAT=xxxx
+
+   The value is either "double" (normal for 32- and 16-bit architectures)
+   or "float" (normal for 64-bit architectures).
+
+   C-Kermit can be configured to use high-precision file-transfer timers
+   for more accurate statistics. This feature is enabled with:
+
+  -DGFTIMER
+
+   and disabled with:
+
+  -DNOGFTIMER
+
+   If you try to build with -DGFTIMER but you get compilation errors,
+   either fix them (and send email to kermit@columbia.edu telling what
+   you did), or else give up and use -DNOGFTIMER (or -DNOFLOAT) instead.
+   Hint: depending on your machine architecture, you might have better
+   luck using double than float as the data type for floating-point
+   numbers, or vice versa. Look in [152]ckcdeb.h for the CKFLOAT
+   definition.
+
+   Floating-point arithmetic is also supported in the script programming
+   language. First via the \fpp...() functions, such as \fppadd(), which
+   adds two floating-point numbers, second in S-Expressions. Addition,
+   subtraction, multiplication, and division are always available. But
+   other functions such as logs, raising to powers, sines and cosines,
+   etc, require the C Math library. To include user-level floating-point
+   math you must put:
+
+  -DFNFLOAT
+
+   and in Unix you must link with the Math library:
+
+  LIBS=".... -lm"
+
+   In K95 and VMS, FNFLOAT is defined automatically if CKFLOAT is
+   defined. In Unix, however, FNFLOAT must be added to each makefile
+   target individually, because of the special linking instructions that
+   must also be added to each target.
+
+   Note: S-Expressions require FNFLOAT.
+
+   [ [153]C-Kermit Home ] [ [154]Kermit Home ]
+    ________________________________________________________________________
+
+  14. SPECIAL CONFIGURATIONS
+
+   [ [155]Top ] [ [156]Contents ] [ [157]Previous ]
+
+   As of C-Kermit 7.0, if you build C-Kermit normally, but with -DNOICP
+   (No Interactive Command Parser), you get a program capable of making
+   serial connections (but not dialing) and network connections (if
+   TCPSOCKET or other network option included), and can also transfer
+   files using Kermit protocol, but only via autodownload/upload.
+   Furthermore, if you call the executable "telnet", it will act like
+   Telnet -- using the command-line options. However, in this case there
+   is nothing to escape back to, so if you type Ctrl-\c, it just prints a
+   message to this effect.
+
+   You can also build C-Kermit with -DNOXFER, meaning omit all the
+   file-transfer features. This leaves you with a scriptable
+   communications program that is considerably smaller than the full
+   C-Kermit.
+
+   [ [158]C-Kermit Home ] [ [159]Kermit Home ]
+    ________________________________________________________________________
+
+  APPENDIX I: SUMMARY OF COMPILE-TIME OPTIONS
+
+   [ [160]Top ] [ [161]Contents ]
+
+   These are the symbols that can be specified on the cc command line,
+   listed alphabetically. Others are used internally, including those
+   taken from header files, those defined by the compiler itself, and
+   those inferred from the ones given below. Kermit's SHOW VERSIONS
+   command attempts to display most of these. See [162]ckcdeb.h and
+   [163]ckcnet.h for inference rules. For example SVR3 implies ATTSV,
+   MULTINET implies TCPSOCKET, and so on.
+
+   Here is the complete list of the Kermit-specific compile-time
+   switches:
+
+   ACUCNTRL Select BSD 4.3-style acucntrl() bidirectional tty control.
+   aegis Build for Apollo Aegis (predefined on Apollo systems).
+   AIX370 Build for IBM AIX/370 for IBM mainframes.
+   AIXESA Build for IBM AIX/ESA for IBM mainframes.
+   AIXPS2 Build for IBM AIX 3.0 for PS/2 series (never formally
+   released).
+   AIXRS Build for IBM AIX 3.x on RS/6000.
+   AIX41 Build for IBM AIX 4.x on RS/6000.
+   AMIGA Build for Commodore Amiga with Intuition OS.
+   ATT6300 Build for AT&T 6300 PLUS.
+   ATT7300 Build for AT&T 7300 UNIX PC (3B1).
+   ATTSV Build for AT&T System III or V UNIX.
+   AUX Build for Apple A/UX for the Macintosh.
+   BIGBUFOK OK to use big buffers - "memory is not a problem"
+   BPS_xxxx Enable SET SPEED xxxx
+   BSD29 Build for BSD 2.9 or 2.10.
+   BSD4 Build for BSD 4.2.
+   BSD41 Build for BSD 4.1.
+   BSD43 Build for BSD 4.3.
+   BSD44 Build for BSD 4.4.
+   C70 Build for BBN C/70.
+   CIE Build for CIE Systems 680/20.
+   CKCONINTB4CB Work around prompt-disappears after escape back from
+   CONNECT.
+   CKLEARN Build with support for learned scripts.
+   CKLOGDIAL Enable connection log.
+   CKMAXPATH Maximum length for a fully qualified filename.
+   CKREGEX (misnomer) Include [...] or {xxx,xxx,xxx} matching in
+   ckmatch().
+   CKSYSLOG Enable syslogging.
+   CK_ANSIC Enable ANSI C constructs - prototypes, etc.
+   CK_ANSILIBS Use header files for ANSI C libraries.
+   CK_APC Enable APC execution by CONNECT module.
+   CK_CURSES Enable fullscreen file transfer display.
+   CK_DSYSINI Use system-wide init file, with name supplied by Kermit.
+   CK_DTRCD DTR/CD flow control is available.
+   CK_FAST Build with fast Kermit protocol defaults.
+   CK_FORK_SIG UNIX only: signal() number for CONNECT module forks.
+   CK_IFRO IF REMOTE command is available (and can run in remote mode).
+   CK_INI_A System-wide init file takes precedence over user's.
+   CK_INI_B User's init file takes precedence over the system-wide one.
+   CK_LABELED Include support for SET FILE TYPE LABELED.
+   CK_LBRK This version can send Long BREAK.
+   CK_LINGER Add code to turn of TCP socket "linger" parameter.
+   CK_MKDIR This version has a zmkdir() command to create directories.
+   CK_NAWS Include TELNET Negotiate About Window Size support.
+   CK_NEWTERM Use newterm() rather than initscr() to initialize curses.
+   CK_PAM Include PAM authentication (might also require -lpam).
+   CK_PCT_BAR Fullscreen file transfer display should include
+   "thermometer".
+   CK_POLL System-V or POSIX based UNIX has poll() function.
+   CK_POSIX_SIG Use POSIX signal handing: sigjmp_buf, sigsetjmp,
+   siglongjmp.
+   CK_READ0 read(fd,&x,0) can be used to test TCP/IP connections.
+   CK_REDIR Enable the REDIRECT command.
+   CK_RESEND Include the RESEND command (needs zfseek() + append).
+   CK_RTSCTS RTS/CTS flow control is available.
+   CK_SHADOW Include support for shadow passwords (e.g. for IKSD
+   authentication).
+   CK_SOCKBUF Enable TCP socket-buffer-size-increasing code.
+   CK_SOCKS UNIX only: Build with socks library rather than regular
+   sockets
+   CK_SOCKS5 UNIX only: Build with socks 5 lib rather than regular
+   sockets
+   CK_SPEED Enable control-character unprefixing.
+   CK_SYSINI="xxxxx" Quoted string to be used as system-wide init file
+   name.
+   CK_TIMERS Build with support for dynamically calculated packet
+   timeouts.
+   CK_TMPDIR This version of Kermit has an isdir() function.
+   CK_TTYFD Defined on systems where the communications connection file
+   descriptor (ttyfd) can be passed to other processes as a command-line
+   argument via \v(ttyfd).
+   CK_URL Parse URLs as well as hostnames, etc.
+   CK_XONXOFF Xon/Xoff flow control available.
+   CK_XYZ Include support for XYZMODEM protocols.
+   CK_WREFRESH Curses package includes wrefresh(),clearok() for screen
+   refresh.
+   CKFLOAT=type Floating-point data type, "double" or "float".
+   CKTYP_H=xxx Force include of xxx as <types.h> file.
+   CLSOPN When hanging up a tty device, also close and reopen it.
+   CMDDEP Maximum recursion depth for self-referential user-defined fn's.
+   COHERENT Build for Mark Williams Coherent UNIX
+   CONGSPD Define if this version has congspd() routine in ck?tio.c
+   datageneral Build for Data General AOS/VS or AOS/VS II
+   DCLPOPEN popen() is available but needs to be declared
+   DEC_TCPIP Build with support for DEC TCP/IP (UCX) for (Open)VMS
+   DGUX430 Build for DG/UX 4.30
+   DGUX540 Build for DG/UX 5.40
+   DEFPAR=x Default parity, 0, 'e', 'o', 'm', or 's'.
+   DFTTY=xxx Default communications device name.
+   DIRENT UNIX directory structure to be taken from <dirent.h>.
+   DIRPWDRP Prompt for password in REMOTE CWD command.
+   DTILDE Include UNIX ~ notation for username/home-directory
+   DYNAMIC Allocate file transfer packet buffers dynamically with malloc.
+   ENCORE Build for Encore Multimax computers.
+   EXCELAN Build with excelan TCP/IP.
+   FNFLOAT Include floating-point math functions (logs, sin, cos, exp,
+   etc)
+   FT18 Build for Fortune For:Pro 1.8.
+   FT21 Build for Fortune For:Pro 2.1.
+   GEMDOS Build for Atari ST GEMDOS.
+   GFTIMER Use high-precision floating-point file-transfer timers.
+   GID_T=xxx Group IDs are of type xxx (usually int, short, or gid_t).
+   HADDRLIST If gethostbyname() hostent struct contains a list of
+   addresses.
+   HDBUUCP Build with support for Honey DanBer UUCP.
+   HPUX Build for Hewlett Packard HP-UX.
+   HPUX9 Build for Hewlett Packard HP-UX 9.x.
+   HPUX10 Build for Hewlett Packard HP-UX 10.x.
+   HWPARITY Define if this version can SET PARITY HARDWARE { EVEN,
+   ODD...}
+   I386IX Build for Interactive System V R3.
+   IFDEBUG Add IF stmts "if (deblog)" before "debug()" calls.
+   INADDRX TCP/IP inet_addr() type is struct inaddr, not unsigned long.
+   INTERLAN Build with support for Racal/Interlan TCP/IP.
+   ISDIRBUG System defs of S_ISDIR and S_ISREG have bug, define
+   ourselves.
+   ISIII Build for Interactive System III.
+   IX370 Build for IBM IX/370.
+   KANJI Build with Kanji character-set translation support.
+   LCKDIR UUCP lock directory is /usr/spool/uucp/LCK/.
+   LFDEVNO UUCP lockfile name uses device numbers, as in SVR4.
+   LINUXFSSTND For Linux, use FSSTND UUCP lockfile conventions (default).
+   LOCK_DIR=xxx UUCP lock directory is xxx (quoted string).
+   LOCKF Use lockf() (in addition to lockfiles) on serial lines
+   LONGFN BSD long filenames supported using <dir.h> and opendir().
+   LYNXOS Build for Lynx OS 2.2 or later (POSIX-based).
+   MAC Build for Apple Macintosh with Mac OS.
+   MATCHDOT Make wildcards match filenames that start with period (.)
+   MAXRP=number Maximum receive-packet length.
+   MAXSP=number Maximum send-packet length.
+   MDEBUG Malloc-debugging requested.
+   MINIDIAL Minimum modem dialer support: CCITT, Hayes, Unkown, and None.
+   MINIX Build for MINIX.
+   MIPS Build for MIPS workstation.
+   MULTINET Build with support for TGV MultiNet TCP/IP (VAX/VMS).
+   M_UNIX Defined by SCO.
+   NAP The nap() is available (conflicts with SELECT and USLEEP)
+   NAPHACK The nap() call is available but only as syscall(3112,...)
+   NDIR BSD long filenames supported using <ndir.h> and opendir().
+   NDGPWNAM Don't declare getpwnam().
+   NDSYSERRLIST Don't declare sys_errlist[].
+   NEEDSELECTDEFS select() is avaible but we need to define FD_blah
+   ourselves.
+   NETCMD Build with support for SET HOST /COMMAND and PIPE commands.
+   NEXT Build for NeXT Mach 1.x or 2.x or 3.0, 3.1, or 3.2.
+   NEXT33 Build for NeXT Mach 3.3.
+   NOANSI Disable ANSI C function prototyping.
+   NOAPC Do not include CK_APC code.
+   NOARROWKEYS Exclude code to parse ANSI arrow-key sequences.
+   NOB_xxxx Disable SET SPEED xxxx
+   NOBIGBUF Override BIGBUFOK when it is the default
+   NOBRKC Don't try to refer to t_brkc or t_eof tchars structure members.
+   NOCKFQHOSTNAME Exclude code to get fully qualified hostname in case it
+   causes core dumps.
+   NOCCTRAP Disable Control-C (SIGINT) trapping.
+   NOCKSPEED Disable control-prefix removal feature (SET CONTROL).
+   NOCKTIMERS Build without support for dynamic timers.
+   NOCKXYZ Overrides CK_XYZ.
+   NOCKREGEX Do not include [...] or {xxx,xxx,xxx} matching in ckmatch().
+   NOCMDL Build with no command-line option processing.
+   NOCOTFMC No Close(Open()) To Force Mode Change (UNIX version).
+   NOCSETS Build with no support for character set translation.
+   NOCYRIL Build with no support for Cyrillic character set translation.
+   NOCYRILLIC Ditto.
+   NODEBUG Build with no debug logging capability.
+   NODIAL Build with no DIAL or SET DIAL commands.
+   NODISPO Build to always refuse incoming MAIL or REMOTE PRINT files.
+   DNODISPLAY Build with no file-transfer display.
+   NOESCSEQ Build with no support for ANSI escape sequence recognition.
+   NOFAST Do not make FAST Kermit protocol settings the default.
+   NOFDZERO Do not use file descriptor 0 for remote-mode file transfer.
+   NOFILEH Do not #include <sys/file.h>.
+   NOFLOAT Don't include any floating-point data types or operations.
+   NOFRILLS Build with "no frills" (this should be phased out...)
+   NOFTRUNCATE Include this on UNIXes that don't have ftruncate().
+   NOGETUSERSHELL Include this on UNIXes that don't have getusershell().
+   NOGFTIMER Don't use high-precision floating-point file-transfer
+   timers.
+   NOHEBREW Build with no support for Hebrew character sets.
+   NOHELP Build with no built-in help.
+   NOIKSD Build with IKSD support excluded.
+   NOINITGROUPS Include this on UNIXes that don't have initgroups().
+   NOICP Build with no interactive command parser.
+   NOJC Build with no support for job control (suspend).
+   NOKANJI Build with no support for Japanese Kanji character sets.
+   NOKVERBS Build with no support for keyboard verbs (\Kverbs).
+   NOLATIN2 Build with no ISO Latin-2 character-set translation support.
+   NOLEARN Build with no support for learned scripts.
+   NOLINKBITS Use of S_ISLNK and _IFLNK untrustworthy; use readlink()
+   instead.
+   NOLOCAL Build without any local-mode features: No Making Connections.
+   NOLOGDIAL Disable connection log.
+   NOLOGIN Build without IKSD (network login) support.
+   NOLSTAT Not OK to use lstat().
+   NOMDMHUP Build without "modem-specific hangup" (e.g. ATH0) feature.
+   NOMHHOST Exclude the multihomed-host TCP/IP code (if compilcation
+   errors)
+   NOMINPUT Build without MINPUT command.
+   NOMSEND Build with no MSEND command.
+   NONAWS Do not include TELNET Negotiate About Window Size support.
+   NONET Do not include any network support.
+   NONOSETBUF (See NOSETBUF)
+   NOPARSEN Build without automatic parity detection.
+   NOPIPESEND Disable file transfer using pipes and filters.
+   NOPOLL Override CK_POLL definition.
+   NOPOPEN The popen() library call is not available.
+   NOPURGE Build with no PURGE command.
+   NOPUSH Build with no escapes to operating system.
+   NOREALPATH In UNIX, realpath() function is not available.
+   NORECALL Disable the command-recall feature.
+   NOREDIRECT Disable REDIRECT command.
+   NORENAME Don't use rename() system call, use link()/unlink() (UNIX).
+   NORESEND Build with no RESEND command.
+   NORETRY Build with no command-retry feature.
+   NOSCRIPT Build with no SCRIPT command.
+   NOSELECT Don't try to use select().
+   NOSERVER Build with no SERVER mode and no server-related commands.
+   NOSETBUF Don't make console writes unbuffered.
+   NONOSETBUF DO make console writes unbuffered.
+   NOSETREU setreuid() and/or setregid() not available.
+   NOSHOW Build with no SHOW command (not recommended!).
+   NOSIGWINCH Disable SIGWINCH signal trapping.
+   NOSPL Build with no script programming language.
+   NOSTAT Don't call stat() from mainline code.
+   NOSYMLINK Include this for UNIXes that don't have readlink().
+   NOSYSIOCTLH Do not #include <sys/ioctl.h>.
+   NOSYSTIMEH Co not include <sys/time.h>.
+   NOSYSLOG Disable syslogging code.
+   NOTCPOPTS Build with no SET TCP options or underlying support.
+   NOTLOG Build with no support for transaction logging.
+   NOTM_ISDST Struct tm has no tm_isdst member.
+   NOUNICODE Build with no support for Unicode character-set translation.
+   NOURL Don't parse URLs
+   NOUUCP Build with no UUCP lockfile support (dangerous!).
+   NOWARN Make EXIT WARNING be OFF by default (otherwise it's ON).
+   NOWREFRESH Override built-in definition of CK_WREFRESH (q.v.).
+   NOXFER Build with no Kermit or other file-transfer protocols.
+   NOXMIT Build with no TRANSMIT command.
+   NOXPRINT Disables transparent print code.
+   OLDMSG Use old "entering server mode" message (see [164]ckcmai.c).
+   OLINUXHISPEED Build in old Linux hi-serial-speed code (for Linux <=
+   1.0).
+   OPENBSD Build for OpenBSD.
+   OS2 Build for OS/2.
+   OSF Build for OSF/1.
+   OSFPC Build for OSF/1 on a PC.
+   OSF32 Digital UNIX 3.2 or later.
+   OSF40 Build for Digital UNIX 4.0.
+   OSF50 Build for Digital UNIX 5.0.
+   OSK Build for OS-9.
+   OXOS Build for Olivetti X/OS 2.3.
+   PCIX Build for PC/IX
+   PID_T=xxx Type for pids is xxx (normally int or pid_t).
+   POSIX Build for POSIX: use POSIX header files, functions, etc.
+   _POSIX_SOURCE Disable non-POSIX features.
+   PROVX1 Build for Venix 1.0 on DEC Professional 3xx.
+   PTX Build for Dynix/PTX
+   PWID_T=xxx getpwid() type is xxx.
+   RBSIZ=xxx Define overall size of receive-packet buffer (with DYNAMIC).
+   RDCHK rdchk() system call is available.
+   RENAME rename() system call is available (UNIX).
+   RTAIX Build for AIX 2.2.1 on IBM RT PC.
+   RTU Build for Masscomp / Concurrent RTU.
+   SAVEDUID BSD or other non-AT&T UNIX has saved-setuid feature.
+   SBSIZ=xxx Define overall size of send-packet buffer (use with
+   DYNAMIC).
+   SDIRENT Directory structure specified in <sys/dirent.h>.
+   SELECT select() function available (conflicts with RDCHK and CK_POLL)
+   SELECT_H Include <sys/select.h> for select()-releated definitions.
+   SETEUID BSD 4.4-style seteXid() functions available.
+   SIG_V Type for signal() is void. Used to override normal assumption.
+   SIG_I Type for signal() is int. Used to override normal assumption.
+   SOCKOPT_T Override default data type for get/setsockopt() option
+   length.
+   SOLARIS Build for Solaris.
+   SOLARIS25 Build for Solaris 2.5 or later.
+   SONYNEWS Build for Sony NEWS-OS.
+   STERMIOX <sys/termiox.h> is available.
+   STRATUS Build for Stratus VOS.
+   STRATUSX25 Include Stratus VOS X.25 support.
+   SUN4S5 Build for SUNOS 4.x in the System V R3 environment.
+   SUNOS4 Build for SUNOS 4.0 in the BSD environment.
+   SUNOS41 Build for SUNOS 4.1 in the BSD environment.
+   SUNX25 Build with support for SunLink X.25.
+   SVR3 Build for AT&T System V Release 3.
+   SVR3JC Allow job control support on System V Release 3 UNIX versions.
+   SVR4 Build for AT&T System V Release 4.
+   SW_ACC_ID UNIX only -- swap real & effective ids around access()
+   calls.
+   sxaE50 Build for PFU Compact A Series SX/A TISP.
+   SYSLOGLEVEL=n Force syslogging at given level.
+   SYSTIMEH Include <sys/time.h>.
+   SYSUTIMEH Include <sys/utime.h> for setting file dates (88OPEN)
+   TCPSOCKET Build with support for TCP/IP via Berkeley sockets library.
+   TERMIOX <termiox.h> header file is available (mostly SVR4).
+   TNCODE Include TELNET-specific code.
+   TOWER1 Build for NCR Tower 1632 with OS 1.02.
+   TRS16 Build for Tandy 16/6000.
+   UID_T=xxx Type for uids is xxx (normally int or uid_t).
+   UNIX Must be defined for all UNIX versions.
+   UNIX351M AT&T UNIX 3.51m on the AT&T 7300 UNIX PC.
+   USE_ARROWKEYS Include code to parse ANSI arrow-key sequences.
+   USE_LSTAT OK to use lstat().
+   USE_MEMCPY Define this if memcpy()/memset()/memmove() available.
+   USE_STRERROR Define this if strerror() is available.
+   USLEEP usleep() system call available (conflicts with NAP & SELECT).
+   UTEK Build for Tektronix workstations with UTEK OS.
+   UTIMEH Include <utime.h> for setting file dates (SVR4, POSIX)
+   UTS24 Build for Amdahl UTS 2.4.
+   V7 Build for Version 7 UNIX.
+   VMS Build for VAX/VMS.
+   VOID=xxx VOID type for functions (int or void).
+   VXVE Build for CDC VX/VE 5.2.1.
+   WAIT_T=xxx Type of argument passed to wait().
+   WINTCP Build with Wollongong VAX/VMS TCP/IP (implies TCPSOCKET)
+   WOLLONGONG Build with Wollongong UNIX TCP/IP (implies TCPSOCKET)
+   XENIX Build for Xenix (SCO, Tandy, others).
+   XNDIR Support for BSD long filenames via <sys/ndir.h>.
+   XYZ_INTERNAL Support for XYZMODEM protocols is internal, not external.
+   ZFCDAT Define this if zfcdat() function is available in Kermit.
+   ZILOG Build for Zilog ZEUS.
+   ZJDATE Has zjdate() function that converts date to Julian format.
+   XPRINT Transparent print code included in CONNECT module.
+
+   [ [165]Top ] [ [166]Contents ] [ [167]C-Kermit Home ] [ [168]Kermit
+   Home ]
+     _________________________________________________________________
+
+
+    C-Kermit Configuration Options / [169]The Kermit Project /
+    [170]Columbia University / [171]kermit@columbia.edu / 14 March 2003
+
+References
+
+   1. http://www.columbia.edu/kermit/
+   2. http://www.columbia.edu/
+   3. http://www.columbia.edu/kermit/ckccfg.html
+   4. http://www.columbia.edu/kermit/ckermit.html
+   5. http://www.columbia.edu/kermit/index.html
+   6. http://www.columbia.edu/kermit/ckccfg.html#x1
+   7. http://www.columbia.edu/kermit/ckccfg.html#x2
+   8. http://www.columbia.edu/kermit/ckccfg.html#x3
+   9. http://www.columbia.edu/kermit/ckccfg.html#x4
+  10. http://www.columbia.edu/kermit/ckccfg.html#x5
+  11. http://www.columbia.edu/kermit/ckccfg.html#x6
+  12. http://www.columbia.edu/kermit/ckccfg.html#x7
+  13. http://www.columbia.edu/kermit/ckccfg.html#x8
+  14. http://www.columbia.edu/kermit/ckccfg.html#x9
+  15. http://www.columbia.edu/kermit/ckccfg.html#x10
+  16. http://www.columbia.edu/kermit/ckccfg.html#x11
+  17. http://www.columbia.edu/kermit/ckccfg.html#x12
+  18. http://www.columbia.edu/kermit/ckccfg.html#x13
+  19. http://www.columbia.edu/kermit/ckccfg.html#x14
+  20. http://www.columbia.edu/kermit/ckccfg.html#xa1
+  21. http://www.columbia.edu/kermit/ckuins.html
+  22. http://www.columbia.edu/kermit/ckermit.html
+  23. http://www.columbia.edu/kermit/index.html
+  24. http://www.columbia.edu/kermit/ckccfg.html#top
+  25. http://www.columbia.edu/kermit/ckccfg.html#contents
+  26. http://www.columbia.edu/kermit/ckccfg.html#x2
+  27. http://www.columbia.edu/kermit/ckccfg.html#x0
+  28. http://www.columbia.edu/kermit/ckermit.html
+  29. http://www.columbia.edu/kermit/index.html
+  30. http://www.columbia.edu/kermit/ckccfg.html#top
+  31. http://www.columbia.edu/kermit/ckccfg.html#contents
+  32. http://www.columbia.edu/kermit/ckccfg.html#x3
+  33. http://www.columbia.edu/kermit/ckccfg.html#x1
+  34. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+  35. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+  36. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus3.c
+  37. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+  38. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+  39. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+  40. http://www.columbia.edu/kermit/ckermit.html
+  41. http://www.columbia.edu/kermit/index.html
+  42. http://www.columbia.edu/kermit/ckccfg.html#top
+  43. http://www.columbia.edu/kermit/ckccfg.html#contents
+  44. http://www.columbia.edu/kermit/ckccfg.html#x4
+  45. http://www.columbia.edu/kermit/ckccfg.html#x2
+  46. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+  47. http://www.columbia.edu/kermit/ckuins.html
+  48. http://www.columbia.edu/kermit/ckuins.html#x4
+  49. http://www.columbia.edu/kermit/ckuins.html#x9.2
+  50. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+  51. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+  52. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+  53. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+  54. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.c
+  55. http://www.columbia.edu/kermit/ckermit.html
+  56. http://www.columbia.edu/kermit/index.html
+  57. http://www.columbia.edu/kermit/ckccfg.html#top
+  58. http://www.columbia.edu/kermit/ckccfg.html#contents
+  59. http://www.columbia.edu/kermit/ckccfg.html#x5
+  60. http://www.columbia.edu/kermit/ckccfg.html#x3
+  61. http://www.columbia.edu/kermit/unicode.html
+  62. http://www.columbia.edu/kermit/ckermit.html
+  63. http://www.columbia.edu/kermit/index.html
+  64. http://www.columbia.edu/kermit/ckccfg.html#top
+  65. http://www.columbia.edu/kermit/ckccfg.html#contents
+  66. http://www.columbia.edu/kermit/ckccfg.html#x6
+  67. http://www.columbia.edu/kermit/ckccfg.html#x4
+  68. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
+  69. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
+  70. http://www.columbia.edu/kermit/ckermit.html
+  71. http://www.columbia.edu/kermit/index.html
+  72. http://www.columbia.edu/kermit/ckccfg.html#top
+  73. http://www.columbia.edu/kermit/ckccfg.html#contents
+  74. http://www.columbia.edu/kermit/ckccfg.html#x7
+  75. http://www.columbia.edu/kermit/ckccfg.html#x5
+  76. http://www.columbia.edu/kermit/ckccfg.html#x6.1
+  77. http://www.columbia.edu/kermit/ckccfg.html#x6.2
+  78. http://www.columbia.edu/kermit/ckccfg.html#x6.3
+  79. http://www.columbia.edu/kermit/ckccfg.html#x6.4
+  80. http://www.columbia.edu/kermit/ckccfg.html#x4
+  81. http://www.columbia.edu/kermit/gkermit.html
+  82. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
+  83. ftp://kermit.columbia.edu/kermit/c-kermit/ckcker.h
+  84. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+  85. http://www.columbia.edu/kermit/ckermit.html
+  86. http://www.columbia.edu/kermit/index.html
+  87. http://www.columbia.edu/kermit/ckccfg.html#top
+  88. http://www.columbia.edu/kermit/ckccfg.html#contents
+  89. http://www.columbia.edu/kermit/ckccfg.html#x8
+  90. http://www.columbia.edu/kermit/ckccfg.html#x6
+  91. ftp://kermit.columbia.edu/kermit/c-kermit/ckudia.c
+  92. http://www.columbia.edu/kermit/ckermit.html
+  93. http://www.columbia.edu/kermit/index.html
+  94. http://www.columbia.edu/kermit/ckccfg.html#top
+  95. http://www.columbia.edu/kermit/ckccfg.html#contents
+  96. http://www.columbia.edu/kermit/ckccfg.html#x9
+  97. http://www.columbia.edu/kermit/ckccfg.html#x7
+  98. http://www.columbia.edu/kermit/ckccfg.html#x8.1
+  99. http://www.columbia.edu/kermit/ckccfg.html#x8.2
+ 100. http://www.columbia.edu/kermit/ckccfg.html#x8.3
+ 101. http://www.columbia.edu/kermit/ckccfg.html#x8.1.1
+ 102. http://www.columbia.edu/kermit/ckccfg.html#x8.1.2
+ 103. http://www.columbia.edu/kermit/ckccfg.html#x8.1.3
+ 104. http://www.columbia.edu/kermit/ckccfg.html#x8.1.4
+ 105. http://www.columbia.edu/kermit/ckccfg.html#x8.1.5
+ 106. http://www.columbia.edu/kermit/ckccfg.html#x8.1.6
+ 107. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 108. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.c
+ 109. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.c
+ 110. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.h
+ 111. ftp://kermit.columbia.edu/kermit/c-kermit/ckcftp.c
+ 112. http://www.columbia.edu/kermit/ckermit.html
+ 113. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
+ 114. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 115. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 116. http://www.columbia.edu/kermit/ckccfg.html#x11
+ 117. mailto:kermit@columbia.edu
+ 118. http://www.columbia.edu/kermit/ckermit.html
+ 119. http://www.columbia.edu/kermit/index.html
+ 120. http://www.columbia.edu/kermit/ckccfg.html#top
+ 121. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 122. http://www.columbia.edu/kermit/ckccfg.html#x10
+ 123. http://www.columbia.edu/kermit/ckccfg.html#x8
+ 124. http://www.columbia.edu/kermit/ckermit.html
+ 125. http://www.columbia.edu/kermit/index.html
+ 126. http://www.columbia.edu/kermit/ckccfg.html#top
+ 127. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 128. http://www.columbia.edu/kermit/ckccfg.html#x11
+ 129. http://www.columbia.edu/kermit/ckccfg.html#x9
+ 130. http://www.columbia.edu/kermit/ckuins.html#x11
+ 131. http://www.columbia.edu/kermit/ckuins.html
+ 132. http://www.columbia.edu/kermit/ckermit.html
+ 133. http://www.columbia.edu/kermit/index.html
+ 134. http://www.columbia.edu/kermit/ckccfg.html#top
+ 135. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 136. http://www.columbia.edu/kermit/ckccfg.html#x12
+ 137. http://www.columbia.edu/kermit/ckccfg.html#x10
+ 138. ftp://kermit.columbia.edu/kermit/c-kermit/ckucns.c
+ 139. ftp://kermit.columbia.edu/kermit/c-kermit/ckucon.c
+ 140. http://www.columbia.edu/kermit/ckermit.html
+ 141. http://www.columbia.edu/kermit/index.html
+ 142. http://www.columbia.edu/kermit/ckccfg.html#top
+ 143. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 144. http://www.columbia.edu/kermit/ckccfg.html#x13
+ 145. http://www.columbia.edu/kermit/ckccfg.html#x11
+ 146. http://www.columbia.edu/kermit/ckermit.html
+ 147. http://www.columbia.edu/kermit/index.html
+ 148. http://www.columbia.edu/kermit/ckccfg.html#top
+ 149. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 150. http://www.columbia.edu/kermit/ckccfg.html#x14
+ 151. http://www.columbia.edu/kermit/ckccfg.html#x12
+ 152. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 153. http://www.columbia.edu/kermit/ckermit.html
+ 154. http://www.columbia.edu/kermit/index.html
+ 155. http://www.columbia.edu/kermit/ckccfg.html#top
+ 156. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 157. http://www.columbia.edu/kermit/ckccfg.html#x13
+ 158. http://www.columbia.edu/kermit/ckermit.html
+ 159. http://www.columbia.edu/kermit/index.html
+ 160. http://www.columbia.edu/kermit/ckccfg.html#top
+ 161. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 162. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 163. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 164. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 165. http://www.columbia.edu/kermit/ckccfg.html#top
+ 166. http://www.columbia.edu/kermit/ckccfg.html#contents
+ 167. http://www.columbia.edu/kermit/ckermit.html
+ 168. http://www.columbia.edu/kermit/index.html
+ 169. http://www.columbia.edu/kermit/index.html
+ 170. http://www.columbia.edu/
+ 171. mailto:kermit@columbia.edu
diff --git a/ckermit-8.0.211/ckcdeb.h b/ckermit-8.0.211/ckcdeb.h
new file mode 100644
index 0000000..31f9c55
--- /dev/null
+++ b/ckermit-8.0.211/ckcdeb.h
@@ -0,0 +1,6369 @@
+/*  C K C D E B . H  */
+
+/*
+  Tue Apr  6 14:00:16 2004
+
+  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 <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 inlcude all
+  material required by all other C-Kermit modules, including the non-Kermit
+  specific ones.
+*/
+
+#ifndef CKCDEB_H			/* Don't include me more than once. */
+#define CKCDEB_H
+
+#ifdef OS2
+#include "ckoker.h"
+#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 */
+
+/* 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 */
+    long 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 */
+    long 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 */
+};
+
+#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 <sys/types.h>			/* 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 */
+
+#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 */
+
+#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 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 */
+#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 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
+#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 */
+#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 NOFTP
+#define NOFTP
+#endif /* NOFTP */
+#ifndef NOHTTP
+#define NOHTTP
+#endif /* NOHTTP */
+#ifndef NOBROWSER
+#define NOBROWSER
+#endif /* NOBROWSER */
+#ifndef NOFORWARDX
+#define NOFORWARDX
+#endif /* NOFORWARDX */
+#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 OS2
+#define WIN32ONLY
+#endif /* OS2 */
+#endif /* NT */
+
+#ifdef OS2				/* For OS/2 debugging */
+#ifndef OS2ORWIN32
+#define OS2ORWIN32
+#endif /* OS2ORWIN32 */
+#ifdef NT
+#define NOCRYPT
+#include <windows.h>
+#define NTSIG
+#else /* NT */
+#define OS2ONLY
+#include <os2def.h>
+#endif /* NT */
+#ifndef OS2ORUNIX
+#define OS2ORUNIX
+#endif /* OS2ORUNIX */
+#ifndef OS2ORVMS
+#define OS2ORVMS
+#endif /* OS2ORVMS */
+#endif /* OS2 */
+
+#include <stdio.h>			/* Begin by including this. */
+#include <ctype.h>			/* and this. */
+
+/* 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 <dirent.h> */
+#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. <dirent.h> */
+#ifndef SDIRENT
+#define DIRENT
+#endif /* SDIRENT */
+#endif /* DIRENT */
+#ifndef NOFILEH				/* POSIX doesn't use <sys/file.h> */
+#define NOFILEH
+#endif /* NOFILEH */
+#endif /* POSIX */
+
+#ifdef V7
+#ifndef UNIX
+#define UNIX
+#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 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
+#define CK_ANSIC            /* OS/2 supports ANSIC and more extensions */
+#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
+#ifdef __ia64				/* VMS on Itanium */
+#ifndef VMSI64
+#define VMSI64
+#endif	/* VMSI64 */
+#endif	/* __ia64 */
+#ifndef VMS64BIT			/* 64-bit VMS on Itanium or Alpha */
+#ifdef __ia64
+#define VMS64BIT
+#else
+#ifdef __ALPHA
+#define VMS64BIT
+#endif	/* __ia64 */
+#endif	/* __ALPHA */
+#endif	/* VMS64BIT */
+#endif	/* 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
+#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
+#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)
+#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 */
+
+#ifndef VOID				/* Used throughout all C-Kermit */
+#ifdef CK_ANSIC				/* modules... */
+#define VOID void
+#else
+#define VOID int
+#endif /* CK_ANSIC */
+#endif /* VOID */
+
+/* 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 <signal.h>
+#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
+#define CK_TAPI
+#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 <sys/time.h> */
+
+#ifndef NOTIMEH				/* <time.h> */
+#ifndef TIMEH
+#define TIMEH
+#endif /* TIMEH */
+#endif /* NOTIMEH */
+
+#ifndef NOSYSTIMEH			/* <sys/time.h> */
+#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			/* <sys/timeb.h> */
+#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 */
+
+#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 *, long));
+#define tlog(a,b,c,d) if (tralog && tlogfmt) dotlog(a,b,c,d)
+_PROTOTYP(VOID doxlog,(int, char *, long, int, int, char *));
+#endif /* TLOG */
+
+/* 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 */
+#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
+#ifdef HAVE_BAUDBOY			/* Red Hat Linux >= 7.2 */
+#define USETTYLOCK
+#endif /* HAVE_BAUDBOY */
+#endif /* USE_UU_LOCK */
+#endif /* AIXRS */
+#endif /* USETTYLOCK */
+#endif /* NOTTYLOCK */
+
+/* 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
+#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 */
+#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
+
+#ifndef CKFLOAT
+#ifdef __alpha
+/* Don't use double on 64-bit platforms -- bad things happen */
+#define CKFLOAT float
+#define CKFLOAT_S "float"
+#else
+#define CKFLOAT double
+#define CKFLOAT_S "double"
+#endif /* __alpha */
+#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 */
+/* Add more here... */
+#endif /* CKHTTP */
+#ifndef CKHTTP				/* If CKHTTP not defined yet */
+#define NOHTTP				/* then define HOHTTP */
+#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
+#endif /* NO_SSL */
+#endif /* _M_PPC */
+#ifndef NO_KERBEROS
+#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 /* 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.
+*/
+
+#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 */
+
+#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 */
+
+/* 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 OS2
+#ifdef NT
+#ifdef PCFONTS				/* PC Font support */
+#undef PCFONTS
+#endif /* PCFONTS */
+#ifdef NPIPE				/* Named Pipes communication */
+#undef NPIPE
+#endif /* NPIPE */
+#ifdef OS2PM				/* Presentation Manager */
+#undef OS2PM
+#endif /* OS2PM */
+#ifdef CK_REXX				/* Rexx */
+#undef CK_REXX
+#endif /* CK_REXX */
+#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
+#else
+#ifdef HPUX
+#define BPS_115K
+#else
+#ifdef __linux__
+#define BPS_115K
+#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 */
+
+#ifdef BPS_921K				/* Maximum speed defined */
+#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 /* 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 <termiox.h> */
+#ifndef CK_RTSCTS
+#define CK_RTSCTS
+#endif /* CK_RTSCTS */
+#ifndef CK_DTRCD
+#define CK_DTRCD
+#endif /* CK_DTRCD */
+#else
+#ifdef STERMIOX				/* Sys V R4 <sys/termiox.h> */
+#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 <sys/termios.h> */
+#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 <errno.h>			/* 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 <errno.h>
+#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 <errno.h>
+#else
+/*
+  The following declaration would cause problems for VMS and OS/2, in which
+  errno is an "extern volatile int noshare"...
+*/
+ extern int errno;			/* Needed by most modules. */
+#endif /* __GLIBC__ */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* STRATUS */
+#endif /* _CRAY */
+
+#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
+#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 in 1998 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 */
+
+#ifndef DEBUG
+/* Compile all the debug() statements away.  Saves a lot of space and time. */
+#define debug(a,b,c,d)
+#define hexdump(a,b,c)
+/* Now define the debug() macro. */
+#else /* DEBUG */
+_PROTOTYP(int dodebug,(int,char *,char *,long));
+_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),(long)d)
+#define hexdump(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),(long)d):0))
+#define hexdump(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),(long)d):0)
+#define hexdump(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),(long)d)
+#define hexdump(a,b,c) dohexdump((CHAR *)(a),(CHAR *)(b),c)
+#endif /* IFDEBUG */
+#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 <sys/file.h>... */
+
+#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 */
+
+/* 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, <stdlib.h> no longer includes <types.h>.
+  But before that an elaborate workaround is required, which results in
+  including <types.h> sometimes but not others, evidently depending on whether
+  <types.h> protects itself against multiple inclusion, which in turn probably
+  differentiates between DECC <types.h> and TGV <types.h>.  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 <sys/types.h>
+#ifdef IF_DOT_H
+#ifndef MULTINET
+#include <if.h>				/* 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 <types.h>
+#else					/* General case, not OS-9 */
+#ifndef CKTYP_H
+#ifndef VMS
+#ifndef MAC
+#ifndef AMIGA
+#define CKTYP_H <sys/types.h>
+#endif /* AMIGA */
+#endif /* MAC */
+#endif /* VMS */
+#endif /* CKTYP_H */
+
+#ifdef GEMDOS
+#undef CKTYP_H
+#include <types.h>
+#endif /* GEMDOS */
+
+#ifdef OS2
+#undef CKTYP_H
+#include <sys/types.h>
+#endif /* OS2 */
+
+#ifdef CKTYP_H				/* Include it. */
+#ifdef COHERENT				/* Except for COHERENT */
+#include <unistd.h>
+#include <sys/types.h>
+#else
+#ifdef datageneral			/* AOS/VS */
+#include <sys/types.h>
+#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 */
+
+/*
+  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 <sys/wait.h>
+#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 <sys/wait.h>
+#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) );
+_PROTOTYP( int zchkpid, (unsigned long) );
+#endif	/* UNIX */
+#ifdef CKEXEC
+_PROTOTYP( VOID z_exec, (char *, char **, int) );
+#endif /* CKEXEC */
+_PROTOTYP( int chkfn, (int) );
+_PROTOTYP( long zchki, (char *) );
+#ifdef VMSORUNIX
+_PROTOTYP( long zgetfs, (char *) );
+#else
+#ifdef OS2
+_PROTOTYP( long 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
+_PROTOTYP( int nzxpand, (char *, int) );
+#else /* NZXPAND */
+_PROTOTYP( int zxpand, (char *) );
+#endif /* NZXPAND */
+_PROTOTYP( int znext, (char *) );
+#ifdef ZXREWIND
+_PROTOTYP( int zxrewind, (void) );
+#endif /* ZXREWIND */
+_PROTOTYP( int zchkspa, (char *, long) );
+_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 *) );
+#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, (long) ) ;
+#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 */
+#define 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 <fcntl.h>
+#include <io.h>
+#ifdef __EMX__
+#ifndef __32BIT__
+#define __32BIT__
+#endif /* __32BIT__ */
+#include <sys/timeb.h>
+#else /* __EMX__ */
+#include <direct.h>
+#undef SIGALRM
+#ifndef SIGUSR1
+#define SIGUSR1 7
+#endif /* SIGUSR1 */
+#define SIGALRM SIGUSR1
+_PROTOTYP( unsigned alarm, (unsigned) );
+_PROTOTYP( unsigned sleep, (unsigned) );
+#endif /* __EMX__ */
+_PROTOTYP( unsigned long 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 <string.h>.
+  Otherwise, skip the prototypes.
+*/
+#include <string.h>
+
+/*
+  Prototypes for other commonly used library functions, such as
+  malloc, free, getenv, atol, atoi, and exit.  Otherwise, no prototypes.
+*/
+#include <stdlib.h>
+#ifdef DIAB /* DIAB DS90 */
+/* #include <commonC.h>  */
+#include <sys/wait.h>
+#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 <unixio.h>
+#endif /* VMS */
+
+#ifdef NEXT
+#ifndef NEXT33
+#include <libc.h>
+#endif /* NEXT33 */
+#else  /* NoT NeXT */
+#ifndef AMIGA
+#ifndef OS2
+#ifdef STRATUS
+#include <c_utilities.h>
+#else /* !STRATUS */
+#ifndef OSKXXC
+#include <unistd.h>
+#endif /* OSKXXC */
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif /* HAVE_CRYPT_H */
+#endif /* STRATUS */
+#endif /* OS2 */
+#endif /* AMIGA */
+#endif /* NEXT */
+
+#else /* Not ANSI libs... */
+
+#ifdef MAC
+#include <String.h>
+#include <StdLib.h>
+#endif /* MAC */
+
+#ifdef HPUX
+#ifndef HPUXPRE65
+#include <unistd.h>
+#endif /* HPUXPRE65 */
+#endif /* HPUX */
+
+#ifdef SUNOS41
+#include <unistd.h>
+#include <stdlib.h>
+#else
+#ifndef MAC
+/*
+  It is essential that these are declared correctly!
+  Which is not always easy.  Take malloc() for instance ...
+*/
+#ifdef PYRAMID
+#ifdef SVR4
+#ifdef __STDC__
+#define SIZE_T_MALLOC
+#endif /* __STDC__ */
+#endif /* SVR4 */
+#endif /* PYRAMID */
+/*
+  Maybe some other environments need the same treatment for malloc.
+  If so, define SIZE_T_MALLOC for them here or in compiler CFLAGS.
+*/
+#ifdef SIZE_T_MALLOC
+_PROTOTYP( void * malloc, (size_t) );
+#else
+_PROTOTYP( char * malloc, (unsigned int) );
+#endif /* SIZE_T_MALLOC */
+
+_PROTOTYP( char * getenv, (char *) );
+_PROTOTYP( long atol, (char *) );
+#endif /* !MAC */
+#endif /* SUNOS41 */
+#endif /* CK_ANSILIBS */
+
+/*
+  <sys/param.h> 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 <sys/param.h>
+#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 */
+
+/* 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 MAXPATHLEN			/* (it probably isn't) */
+#define CKMAXPATH MAXPATHLEN
+#else
+#ifdef PATH_MAX				/* POSIX */
+#define CKMAXPATH PATH_MAX
+#else
+#ifdef MAC
+#define CKMAXPATH 63
+#else
+#ifdef pdp11
+#define CKMAXPATH 255
+#else
+#ifdef UNIX				/* Even though some are way less... */
+#define CKMAXPATH 1024
+#else
+#ifdef VMS
+#define CKMAXPATH 675			/* (derivation is complicated...) */
+#else
+#ifdef STRATUS
+#define CKMAXPATH 256			/* == $MXPL from PARU.H */
+#else
+#ifdef datageneral
+#define CKMAXPATH 256			/* == $MXPL from PARU.H */
+#else
+#define CKMAXPATH 255
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* pdp11 */
+#endif /* MAC */
+#endif /* PATH_MAX */
+#endif /* MAXPATHLEN */
+#endif /* CKMAXPATH */
+
+/* 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 ISDIRSEP(c) ((c)=='/')
+#else
+#ifdef OS2
+#define DIRSEP '/'
+#define ISDIRSEP(c) ((c)=='/'||(c)=='\\')
+#else
+#ifdef datageneral
+#define DIRSEP ':'
+#define ISDIRSEP(c) (((c)==':')||((c)=='^')||((c)=='='))
+#else
+#ifdef STRATUS
+#define DIRSEP '>'
+#define ISDIRSEP(c) ((c)=='>')
+#else
+#ifdef VMS
+#define DIRSEP ']'			/* (not really) */
+#define ISDIRSEP(c) ((c)==']'||(c)==':')
+#else
+#ifdef MAC
+#define DIRSEP ':'
+#define ISDIRSEP(c) ((c)==':')
+#else
+#ifdef AMIGA
+#define DIRSEP '/'
+#define ISDIRSEP(c) ((c)=='/'||(c)==':')
+#else
+#ifdef GEMDOS
+#define DIRSEP '\\'
+#define ISDIRSEP(c) ((c)=='\\'||(c)==':')
+#else
+#define DIRSEP '/'
+#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
+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 NETPTY
+_PROTOTYP( int do_pty, (char *));
+_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 */
+
+#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 */
+
+_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));
+#endif /* NT */
+
+#include "ckclib.h"
+
+/* End of ckcdeb.h */
+#endif /* CKCDEB_H */
diff --git a/ckermit-8.0.211/ckcfn2.c b/ckermit-8.0.211/ckcfn2.c
new file mode 100644
index 0000000..06b97a2
--- /dev/null
+++ b/ckermit-8.0.211/ckcfn2.c
@@ -0,0 +1,3297 @@
+/*  C K C F N 2  --  System-independent Kermit protocol support functions... */
+
+/*  ...Part 2 (continued from ckcfns.c)  */
+
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 -- 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 */
+#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, bctl, rsn, rln, maxtry, size;
+extern int 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, ffc, flci, flco, tlci, tlco, tfc, speed;
+extern long filcps, tfcps;
+
+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
+getrtt(nakstate, n) int nakstate, n; {
+    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. */
+#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. */
+#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. */
+		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.
+*/
+    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
+chktimo(timo,flag) int timo, flag; {
+    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;
+    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);
+	if (pkttyp != 'D') {		/* Data packets would be too long */
+	    debug(F111,"spack data",data,data);
+	    debug(F111,"spack d",d,d);
+	}
+	debug(F101,"spack len","",len);
+	debug(F101,"spack copy","",copy);
+    }
+#endif /* DEBUG */
+
+    longpkt = (len + bctl + 2) > 94;	/* Decide whether it's a long packet */
+    mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */
+    k = sseqtbl[n];			/* Packet structure info for pkt n */
+#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 */
+    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 */
+    if (longpkt) {			/* Long packet? */
+	int x;				/* Yes, work around SCO Xenix/286 */
+#ifdef CKTUNING
+	unsigned int chk;
+#endif /* CKTUNING */
+	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 mydata[lp] = tochar(j+2);	/* Normal LEN */
+/*
+  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 == 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
+chk1(pkt,len) register CHAR *pkt; register int len; {
+    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(F101,"chk1","",chk);
+    return((int) chk);
+}
+
+/*  C H K 2  --  Compute the numeric sum of all the bytes in the packet.  */
+
+unsigned int
+chk2(pkt,len) register CHAR *pkt; register int len; {
+    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
+chk3(pkt,parity,len) register CHAR *pkt; int parity; register int len; {
+    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
+chk3(pkt,len) register CHAR *pkt; register int len; {
+    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
+ackns(n,s) int n; CHAR *s; {		/* Acknowledge packet n */
+    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
+ackn(n) int n; {			/* Send ACK for packet number n */
+    return(ackns(n,(CHAR *)""));
+}
+
+int
+ack1(s) CHAR *s; {			/* Send an ACK with data. */
+    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
+nack(n) int n; {
+    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
+rcalcpsz() {
+
+#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 / (long) 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
+resend(n) int n; {			/* Send packet n again. */
+    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.
+*/
+		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 *)"<reconstructed>",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
+errpkt(reason) CHAR *reason; {		/* ...containing the reason given */
+    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
+srinit(reget, retrieve, opkt) int reget, retrieve, opkt; {
+    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 == 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
+chkspkt(buf) char *buf; {
+    int buflen;
+    int len = -1;
+    CHAR chk;
+    char type = 0;
+    char *s = buf;
+
+    if (!buf) return(0);
+    buflen = strlen(buf);
+    if (buflen < 5) return(0);		/* Too short */
+    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;
+    if (xunchar(chk) != chk1((CHAR *)(buf+1),buflen-2)) /* Check it */
+      return(0);
+    *s = chk;
+    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 > -1 && 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 *)"<timeout>",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,"<timeout>",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 *)"<crunched:hdr>",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 *)"<crunched:len>",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 *)"<crunched:seq>",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 *)"<echo:ignored>",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.
+*/
+    if (type == 'I' || type == 'S') {	/* 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;
+	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 *)"<overflow>",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 *)"<crunched:chk1>",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 *)"<crunched:chk2>",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 *)"<crunched:chk3>",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 *)"<crunched:chkb>",0);
+	    xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
+	    return('Q');
+	}
+	break;
+      default:			/* Shouldn't happen... */
+	freerbuf(k);
+	logpkt('r',-1,(CHAR *)"<crunched:chkx>",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 *)"<duplicate>",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) */
+
+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)  ","",(long) tsecs);
+    if (tsecs > 0) {
+	long lx;
+	lx = (tfc * 10L) / (long) tsecs;
+	tlog(F101," effective data rate     ","",lx/10L);
+    }
+#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 */
diff --git a/ckermit-8.0.211/ckcfn3.c b/ckermit-8.0.211/ckcfn3.c
new file mode 100644
index 0000000..c499421
--- /dev/null
+++ b/ckermit-8.0.211/ckcfn3.c
@@ -0,0 +1,2559 @@
+/*  C K C F N 3  --  Packet buffer management for C-Kermit  */
+
+/* (plus assorted functions tacked on at the end) */
+
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 -- 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"
+
+/*  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
+ckmkdir(fc,s,r,m,cvt) int fc; char * s; char ** r; int m; int cvt; {
+    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;
+extern long sendstart, calibrate, 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;
+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 fsize, filcnt, ffc, tfc;
+
+#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
+inibufs(s,r) int s, r; {
+#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
+makebuf(slots,bufsiz,buf,xx)
+/* makebuf */ int slots, bufsiz; CHAR buf[]; struct pktinfo *xx; {
+
+    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
+mksbuf(slots) int slots; {
+    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
+mkrbuf(slots) int slots; {
+    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
+window(n) int n; {
+    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
+getsbuf(n) int n; {			/* Allocate a send-buffer */
+    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
+freesbuf(n) int n; {			/* Release send-buffer for packet n. */
+    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
+freerbuf(i) int i; {			/* Release receive-buffer slot "i". */
+    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
+freerpkt(seq) int seq; {
+    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
+chkwin(n,bottom,slots) int n, bottom, slots; {
+    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
+sattr(xp, flag) int xp, flag; {		/* Send Attributes */
+
+    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;
+	max = maxdata();		/* Get maximum data field length */
+	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 > -1L) {
+	sprintf((char *) &data[i+2],"%ld",x.lengthk); /* 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++;
+	}
+    }
+    /* File length in bytes */
+    if (atleno && !done[xunchar(c = '1')] && x.length > -1L) {
+	sprintf((char *) &data[i+2],"%ld",x.length); /* 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++;
+	}
+    }
+#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 *
+getreason(s) char *s; {			/* Decode attribute refusal reason */
+    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
+rsattr(s) CHAR *s; {			/* Read response to attribute packet */
+    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; long z; CHAR *p;
+	p = s + 1;
+	n = xunchar(*p++);
+	debug(F101,"rsattr RESEND n","",n);
+	z = 0L;
+	while (n-- > 0)			/* We assume the format is good. */
+	  z = 10L * z + (long) (*p++ - '0');
+	debug(F101,"rsattr RESEND z","",z);
+	if (z > 0L) sendstart = z;
+	debug(F101,"rsattr RESEND sendstart","",sendstart);
+	if (sendstart > 0L)
+	  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);
+}
+
+long rs_len = 0L;			/* Length of file being resent to */
+
+/*
+  Get attributes from incoming A packet.  Returns:
+   0 on success, file is to be accepted
+  -1 on failure, file is to be refused
+*/
+int
+gattr(s, yy) CHAR *s; struct zattr *yy; { /* Read incoming attribute packet */
+    char c, d;
+    char *ff;
+    int aln, i;
+
+#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) {
+	  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 = atol(abuf);	/* Convert to number */
+	    break;
+
+	  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 = 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 > 0L) {
+			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 '1':			/* File length in bytes */
+	    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);
+	    yy->length = atol(abuf);	/* Convert to number */
+	    debug(F111,"gattr length",abuf,(int) yy->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 file length now, because we also need to know the file type */
+    /* in case zchkspa() differentiates text and binary (VMS version does) */
+
+    if (atleni) {			/* Length attribute enabled? */
+	if (yy->length > -1L) {		/* 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 > -1L) {	/* Length in K attribute rec'd? */
+	    if (!zchkspa(ff,(yy->lengthk * 1024))) {
+		retcode = -1;		/* Check space */
+		*rp++ = '!';
+		if (!opnerr) tlog(F100," refused: length K","",0);
+	    }
+	}
+    }
+    if (yy->length > -1L) {		/* Remember the file size */
+	fsize = yy->length;
+    } else if (yy->lengthk > -1L) {
+	fsize = yy->lengthk * 1024L;
+    } else fsize = -1L;
+
+#ifdef DEBUG
+    if (deblog) {
+	sprintf(abuf,"%ld",fsize);	/* safe */
+	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 */
+	    sprintf(rpbuf+2,"%ld",rs_len); /* Reply with length of file */
+	    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
+initattr(yy) struct zattr *yy; {
+    yy->lengthk = yy->length = -1L;
+    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
+adebu(f,zz) char *f; struct zattr *zz; {
+#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
+opena(f,zz) char *f; struct zattr *zz; {
+    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 = 0L;				/* 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 > -1L)
+#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
+openc(n,s) int n; char * s; {
+    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
+canned(buf) CHAR *buf; {
+    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
+openi(name) char *name; {
+#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
+openo(name,zz,fcb) char *name; struct zattr *zz; struct filinfo *fcb; {
+    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
+opent(zz) struct zattr *zz; {
+    int x;
+    ffc = tfc = 0L;
+    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
+ckopenx(zz) struct zattr *zz; {
+    ffc = tfc = 0L;			/* 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
+clsif() {
+    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) {
+	    long 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 = 0L;			/* 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
+clsof(disp) int disp; {
+    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 = 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 */
diff --git a/ckermit-8.0.211/ckcfns.c b/ckermit-8.0.211/ckcfns.c
new file mode 100644
index 0000000..53ea236
--- /dev/null
+++ b/ckermit-8.0.211/ckcfns.c
@@ -0,0 +1,7108 @@
+char *fnsv = "C-Kermit functions, 8.0.223, 1 May 2003";
+
+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 <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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.
+*/
+/*
+ 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 <os2.h>
+#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 long ffc;
+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 OS2ORUNIX
+_PROTOTYP( long zfsize, (char *) );
+#endif /* OS2ORUNIX */
+
+#ifdef OS2
+#include <io.h>
+#ifdef OS2ONLY
+#include <os2.h>
+#endif /* OS2ONLY */
+#endif /* OS2 */
+
+#ifdef VMS
+#include <errno.h>
+#endif /* VMS */
+
+/* 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, 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 long filcnt, flci, flco, tlci, tlco, tfc, fsize, sendstart, rs_len;
+extern long filrej, oldcps, cps, peakcps, ccu, ccp, calibrate, 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;
+
+#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 */
+
+/* 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 };
+long sndsmaller = -1L;
+long sndlarger  = -1L;
+
+/* 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 1024
+#else
+#define CMDSTRL 256
+#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.
+  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 94 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 98 to return length of encoded string.
+*/
+    int m, rc, slen; char *p;
+    if (!data) {			/* Watch out for null pointers. */
+	debug(F100,"SERIOUS ERROR: encstr data == NULL","",0);
+	return(-1);
+    }
+    if (!s) s = (CHAR *)"";		/* Ditto. */
+    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 spsiz","",spsiz);
+    rc = getpkt(spsiz,0);		/* Fill a packet from the string. */
+    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 long 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 = 0L;
+	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 == 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 == 0L && 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[1-swapping];
+                output.bytes[1] = uc.x_char[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)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 == 0 && 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 == 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 == 0L) 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 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
+lslook(b) unsigned int b; {		/* Locking Shift Lookahead */
+    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
+bgetpkt(bufmax) int bufmax; {
+    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 */
+    bufmax = maxdata();			/* Get maximum data length */
+
+#ifdef DEBUG
+    if (deblog)
+      debug(F101,"bgetpkt bufmax","",bufmax);
+#endif /* DEBUG */
+
+    if (first == 1) {			/* If first character of this file.. */
+	ffc = 0L;			/* 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
+dofilcrc(c) int c; {			/* Accumulate file crc */
+    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 = 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 == 0) {
+	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 == 0)		/* 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 == 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 == 0L)		/* 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.
+*/
+	  xx = (what & W_SEND) ? xut : xuf;
+	  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(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)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++] = 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
+getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
+    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 */
+
+    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.
+*/
+    bufmax = maxdata();			/* Get maximum data length */
+
+    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 = 0L;			/* 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
+		 * "~ <n-1> 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[CR]) {
+		*dp++ = myctlq;		/* Insert carriage return directly */
+		*dp++ = 'M';
+		ccp++;
+	    } else {
+		*dp++ = 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
+tinit(flag) int flag; {
+    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) {
+	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
+rinit(d) CHAR *d; {
+    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 = 0L;		/* File chars in and out */
+#ifdef GFTIMER
+    fpfsecs = 0.0;
+#endif /* GFTIMER */
+    tfc = tlci = tlco = 0L;		/* Total file, line chars in & out */
+    ccu = ccp = 0L;			/* Control-char statistics */
+#ifdef COMMENT
+    fsize = -1L;			/* File size */
+#else
+    if (!(what & W_SEND))
+      fsize = -1L;
+    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. */
+    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 */
+long ofn1len = 0L;
+int opnerr;				/* Flag for open error */
+
+int					/* Returns success ? 1 : 0 */
+rcvfil(n) char *n; {
+    extern int en_cwd;
+    int i, skipthis;
+    char * n2;
+    char * dispo;
+#ifdef OS2ONLY
+    char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */
+#endif /* OS2ONLY */
+#ifdef DTILDE
+    char *dirp;
+#endif /* DTILDE */
+    int dirflg, x, y;
+#ifdef PIPESEND
+    extern char * rcvfilter;
+#endif /* PIPESEND */
+#ifdef CALIBRATE
+    extern int dest;
+    int csave;
+    csave = calibrate;			/* So we can decode filename */
+    calibrate = 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 != -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 = 0L;				/* Init per-file counters */
+    cps = oldcps = 0L;
+    rs_len = 0L;
+    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
+reof(f,yy) char *f; struct zattr *yy; {
+    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.w.  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
+sfile(x) int x; {
+#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 > 0L)		/* 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 = 0L;				/* 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 */
+#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
+szeof(s) CHAR *s; {
+    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
+seof(x) int x; {
+    char * s;
+/*
+  ckcpro.w, 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
+sxeof(x) int x; {
+    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 wierd */
+					/* addressing foulup in spack()... */
+					/* (which might be fixed now...) */
+
+CHAR *
+rpar() {
+    char *p;
+    int i, x, max;
+    extern int sprmlen;
+
+    max = maxdata();			/* Biggest data field I can send */
+    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. */
+}
+
+int
+spar(s) CHAR *s; {			/* Set parameters */
+    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]) : CR;
+    if ((seol < 1) || (seol > 31)) seol = 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 > 4)) x = 1;
+    }
+    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]);
+	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);
+	for (y = 10; (xunchar(s[y]) & 1) && (biggest >= y); y++);
+	debug(F101,"spar y","",y);
+    }
+
+/* Long Packets */
+    debug(F101,"spar lpcapu","",lpcapu);
+    if (lpcapu) {
+        if (biggest > y+1) {
+	    x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
+	    debug(F101,"spar lp len","",x);
+	    if (spsizf) {		/* If overriding negotiations */
+		spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
+	    } else {			         /* otherwise */
+		spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
+	    }
+	    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 partnet'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 to hard to explain).
+*/
+int
+gnfile() {
+    int i = 0, x = 0; long y = 0L;
+    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 = -1L;			/* Initialize file size */
+    fullname[0] = NUL;
+    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);
+    }
+#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 = -1L;			/* 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 */
+
+    y = -1L;				/* Loop exit (file size) variable */
+    while (y < 0L) {			/* 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);
+#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);
+		    strncat(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) > -1) {
+			/*
+			   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 */
+	    y = zchki(fullname);	/* Check if file readable */
+	    debug(F111,"gnfile zchki",fullname,y);
+	    retcode = (int) y;		/* Possible return code */
+	    if (y == -2L && dodirstoo) {
+		y = 0L;
+	    }
+	    if (y < 0L) {
+		gnferror = (int) y;
+		debug(F101,"gnfile gnferror C","",gnferror);
+	    }
+	    if (y == -1L) {		/* 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;
+	    } else if (y < 0) {
+		if (y == -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 = y;
+		xx = fileselect(fullname,
+				sndafter, sndbefore,
+				sndnafter,sndnbefore,
+				sndsmaller,sndlarger,
+				skipbup,
+				NSNDEXCEPT,sndexcept);
+		debug(F111,"gnfile fileselect",fullname,xx);
+		if (!xx) {
+		    y = -1L;
+		    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);
+		y = -1L;
+		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 long nbytes  =  0;
+
+int
+sndstring(p) char * p; {
+#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 *
+xnm(x) int x; {
+#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 (EXPERIMENTAL)\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 */
+}
+
+/*
+   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
+sndtype(file) char * file; {
+#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 */
+    long 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,"<DIR>",dstr,name);
+#else
+	    if (p)
+	      sprintf((char *)linebuf,
+		      "%10s%-10s  %s  %s\n",p,"<DIR>",dstr,name);
+	    else
+	      sprintf((char *)linebuf,
+		      "%-10s  %s  %s\n", "<DIR>", dstr, name);
+#endif /* VMS */
+	} else {			/* Regular file */
+#ifdef VMS
+	    sprintf((char *)linebuf,
+		    "%-22s%10ld  %s  %s\n", p, len, dstr, name);
+#else
+	    if (p)
+	      sprintf((char *)linebuf,
+		      "%10s%10ld  %s  %s%s%s\n",
+		      p, len, dstr, name,
+		      *lnk ? " -> " : "",
+		      lnk
+		      );
+	    else
+	      sprintf((char *)linebuf,
+		      "%10ld  %s  %s%s%s\n",
+		      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 == 1)
+           bytetag = "byte";
+        sprintf((char *)funcbuf,
+           "%sSummary: %ld %s, %ld %s, %ld %s%s",
+           blankline,
+           ndirs,
+           dirtag,
+           nfiles,
+           filetag,
+           nbytes,
+           bytetag,
+           endline);
+#else
+        sprintf((char *)funcbuf,
+		"%sSummary: %ld director%s, %ld file%s, %ld byte%s%s",
+		blankline,
+		ndirs,
+		(ndirs == 1) ? "y" : "ies",
+		nfiles,
+		(nfiles == 1) ? "" : "s",
+		nbytes,
+		(nbytes == 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
+snddir(spec) char * spec; {
+#ifndef NOSERVER
+    char * p = NULL, name[CKMAXPATH+1];
+    int t = 0, 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 = 0L;
+
+    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. */
+    if ((int)strlen(name) < CMDSTRL - 11) /* Data for X packet. */
+      sprintf(cmdstr,"DIRECTORY %s",name); /* safe */
+    else
+      ckstrncpy(cmdstr,"DIRECTORY",CMDSTRL);
+    first = 1;				/* Init getchx lookahead */
+    funcstr = 1;			/* Just set the flag. */
+    funcptr = nxtdir;			/* And the pointer. */
+    rc = sinit();
+    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, %ld byte%s freed%s",
+		  endline,
+		  nfiles,
+		  (nfiles == 1) ? "" : "s",
+		  nbytes,
+		  (nbytes == 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
+snddel(spec) char * spec; {
+#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 = nbytes = 0L;
+    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];
+    unsigned long 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
+cwd(vdir) char *vdir; {
+    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
+syscmd(prefix,suffix) char *prefix, *suffix; {
+    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
+remset(s) char *s; {
+    extern int c_save, en_del;
+    int len, i, 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);
+	}
+	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
+adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
+    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 */
diff --git a/ckermit-8.0.211/ckcftp.c b/ckermit-8.0.211/ckcftp.c
new file mode 100644
index 0000000..d8d9ddd
--- /dev/null
+++ b/ckermit-8.0.211/ckcftp.c
@@ -0,0 +1,17126 @@
+/*  C K C F T P  --  FTP Client for C-Kermit  */
+
+char *ckftpv = "FTP Client, 8.0.226, 7 Jan 2004";
+
+/*
+  Authors:
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University.
+
+  Copyright (C) 2000, 2004,
+    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) <format>,  E(BCDIC) <format>, I(MAGE), L(OCAL) <bytesize>
+    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 <CRLF>
+    ACCT <SP> <account-information> <CRLF>
+    ALLO <SP> <decimal-integer> [<SP> R <SP> <decimal-integer>] <CRLF>
+    APPE <SP> <pathname> <CRLF>
+    CDUP <CRLF>
+    CWD  <SP> <pathname> <CRLF>
+    DELE <SP> <pathname> <CRLF>
+    FEAT <CRLF>
+    HELP [<SP> <string>] <CRLF>
+    LANG [<SP> <language-tag> ] <CRLF>
+    LIST [<SP> <pathname>] <CRLF>
+    MKD  <SP> <pathname> <CRLF>
+    MLSD [<SP> <pathname>] <CRLF>
+    MLST [<SP> <pathname>] <CRLF>
+    MODE <SP> <mode-code> <CRLF>
+    NLST [<SP> <pathname-or-wildcard>] <CRLF>
+    NOOP <CRLF>
+    OPTS <SP> <commandname> [ <SP> <command-options> ] <CRLF>
+    PASS <SP> <password> <CRLF>
+    PASV <CRLF>
+    PORT <SP> <host-port> <CRLF>
+    PWD  <CRLF>
+    QUIT <CRLF>
+    REIN <CRLF>
+    REST <SP> <marker> <CRLF>
+    RETR <SP> <pathname> <CRLF>
+    RMD  <SP> <pathname> <CRLF>
+    RNFR <SP> <pathname> <CRLF>
+    RNTO <SP> <pathname> <CRLF>
+    SITE <SP> <string> <CRLF>
+    SIZE <SP> <pathname> <CRLF>
+    SMNT <SP> <pathname> <CRLF>
+    STAT [<SP> <pathname>] <CRLF>
+    STOR <SP> <pathname> <CRLF>
+    STOU <CRLF>
+    STRU <SP> <structure-code> <CRLF>
+    SYST <CRLF>
+    TYPE <SP> <type-code> <CRLF>
+    USER <SP> <username> <CRLF>
+*/
+#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 <stdarg.h>
+#else /* CK_ANSIC */
+#include <varargs.h>
+#endif /* CK_ANSIC */
+#include <signal.h>
+#ifdef OS2
+#ifdef OS2ONLY
+#include <os2.h>
+#endif /* OS2ONLY */
+#include "ckowin.h"
+#include "ckocon.h"
+#endif /* OS2 */
+#ifndef ZILOG
+#ifdef NT
+#include <setjmpex.h>
+#ifdef NTSIG
+extern int TlsIndex;
+#endif /* NTSIG */
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#else
+#include <setret.h>
+#endif /* ZILOG */
+#include "ckcsig.h"
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#ifndef NOTIMEH
+#include <time.h>
+#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"
+
+/*
+  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 <sys/time.h>
+#endif /* SYSTIMEH */
+#endif /* NOSYSTIMEH */
+#ifndef NOSYSTIMEBH
+#ifdef SYSTIMEBH
+#include <sys/timeb.h>
+#endif /* SYSTIMEBH */
+#endif /* NOSYSTIMEBH */
+#endif /* DCLTIMEVAL */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#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 SYSUTIMEH
+#include <sys/utime.h>
+#else
+#ifdef UTIMEH
+#include <utime.h>
+#define SYSUTIMEH
+#endif /* UTIMEH */
+#endif /* SYSUTIMEH */
+#endif /* NOSETTIME */
+
+#ifndef SCO_OSR504
+#ifdef SELECT_H
+#include <sys/select.h>
+#endif /* SELECT_H */
+#endif /* SCO_OSR504 */
+
+/* select() dialects... */
+
+#ifdef UNIX
+#define BSDSELECT                       /* BSD select() syntax/semantics */
+#else
+#ifdef OS2                              /* OS/2 or Win32 */
+#ifdef NT
+#define BSDSELECT
+#else /* NT */
+#define IBMSELECT
+#endif /* NT */
+#endif /* OS2 */
+#endif /* UNIX */
+
+/* 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
+#define FTP_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 <gssapi/gssapi.h>
+/*
+  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 <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+static gss_ctx_id_t gcontext;
+#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"
+
+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(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 long fsize, ffc, tfc, filcnt, xfsecs, tfcps, cps, oldcps;
+#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 long sendstart, sndsmaller, sndlarger, rs_len;
+
+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 */
+
+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
+#define sigtype SIGTYP
+typedef sigtype (*sig_t)();
+
+/* 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 long havesize = -1L;
+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;
+static jmp_buf ptcancel;
+static jmp_buf jcancel;
+static int ptabflg = 0;
+
+/* 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 */
+#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 short ftp_port = 0;              /* FTP port */
+#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
+
+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 },
+    { "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) */
+
+/* FTP BUGS */
+
+#define FTB_SV2  1                      /* use SSLv2 */
+
+static struct keytab ftpbugtab[] = {
+    { "use-ssl-v2",     FTB_SV2,        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 */
+    { "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));
+_PROTOTYP(static int fts_cpl,(int));
+_PROTOTYP(static int fts_dpl,(int));
+#ifdef FTP_SECURITY
+_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 *
+strval(s1,s2) char * s1, * s2; {
+    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
+strgetc() {                             /* Helper function for xgnbyte() */
+    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);
+}
+
+static int
+#ifdef CK_ANSIC
+xprintc(char c)
+#else
+xprintc(c) char c;
+#endif /* CK_ANSIC */
+{
+    printf("%c",c);
+    return(0);
+}
+
+static VOID
+bytswap(c0,c1) int * c0, * c1; {
+    int t;
+    t = *c0;
+    *c0 = *c1;
+    *c1 = t;
+}
+#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);
+        strncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
+        strncat(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," ",NULL,NULL);
+    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 */ {
+    int x, z;
+    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;
+            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;
+              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
+ftscreen(n, c, z, s) int n; char c; long z; char * s; {
+    if (displa && fdispla && !backgrd && !quiet && !out2screen) {
+        if (!dpyactive) {
+            ckscreen(SCR_PT,'S',0L,"");
+            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 */
+
+      case FTS_STO: {			/* Server time offset */
+	  char * s, * p = NULL;
+	  int 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);
+#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
+openftp(s,opn_tls) char * s; int opn_tls; {
+    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);
+}
+
+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 */
+    int x;
+    char *s, * acct = "";
+
+    debok = 0;                          /* Don't log */
+    if ((x = cmfld("Remote username or ID","",&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)
+        return(x);
+    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
+doftptyp(type) int type; {              /* TYPE */
+    CHECKCONN();
+    ftp_typ = type;
+    changetype(ftp_typ,ftp_vbm);
+    return(1);
+}
+
+static int
+doftpxmkd(s,vbm) char * s; int vbm; {   /* MKDIR action */
+    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
+doftpmkd() {                            /* MKDIR parse */
+    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
+doftpdir(cx) int cx; {                  /* [V]DIRECTORY */
+    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
+doftpcwd(s,vbm) char * s; int vbm; {    /* CD (CWD) */
+    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 */
+
+/* Used with recursive PUTs; Returns 0 on failure, 1 on success */
+
+static int cdlevel = 0, cdsimlvl = 0;
+
+static int
+syncdir(local,sim) char * local; int sim; {
+    char buf[CKMAXPATH+1];
+    char tmp[CKMAXPATH+1];
+    char msgbuf[CKMAXPATH+64];
+    char c, * p = local, * s = buf, * q = buf;
+    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);
+    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)
+      *q = NUL;                         /* Keep just the path part */
+
+    debug(F110,"ftp syncdir buf",buf,0);
+    if (!strcmp(buf,putpath)) {         /* Same as for previous file? */
+        if (itsadir) {                  /* It's 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,0l,msgbuf);
+                }
+                /* See note above */
+                return(0);
+            } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */
+                return(0);
+            } else {
+                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,0l,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 p",p,0);
+    debug(F110,"ftp syncdir A s",s,0);
+
+    while (*p != NUL && *s != NUL && *p == *s) p++,s++;
+
+    if (*s == '/' && !*p) s++;          /* Don't count initial slash */
+
+    debug(F110,"ftp syncdir B p",p,0);
+    debug(F110,"ftp syncdir B s",s,0);
+
+    /* p and s now point to the leftmost spot where they differ */
+
+    if (*s) {                           /* We have to back up */
+        k = 1;                          /* How many levels */
+        while ((c = *s++)) {            /* Count dirseps */
+            if (c == '/' && *s)
+              k++;
+        }
+        for (i = 0; i < k; i++) {       /* Do that many CDUPs */
+            debug(F111,"ftp syncdir up",p,i+1);
+            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. */
+    }
+    while (p > buf && *p && *p != '/')  /* If in middle of segment */
+      p--;                              /* back up to beginning */
+    if (*p == '/')                      /* and terminate there */
+      p++;
+
+    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,0l,msgbuf);
+                        }
+                        cdsimlvl++;
+                    } else {
+                        if (!doftpxmkd(p,0)) { /* Can't CD - try to create */
+/*
+  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);
+                        }
+                        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,0l,msgbuf);
+                        }
+                        if (!doftpcwd(p,0)) { /* Try again to CD */
+                            quiet = saveq;
+                            return(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
+dbtime(s,xx) char * s; struct tm * xx; { /* Write struct tm to debug log */
+    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
+tmcompare(xx,yy) struct tm * xx, * yy; {
+
+    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
+#ifdef V7
+    struct utimbuf {
+        time_t timep[2];
+    } tp;
+#else
+#ifdef SYSUTIMEH
+#ifdef NT
+    struct _utimbuf tp;
+#else /* NT */
+    struct utimbuf tp;
+#endif /* NT */
+#else
+    struct utimbuf {
+        time_t atime;
+        time_t mtime;
+    } tp;
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+    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
+chkmodtime(local,remote,fc) char * local, * remote; int fc; {
+#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 */
+            tmlocal = gmtime(&statbuf.st_mtime); /* Convert to struct tm */
+#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
+getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)
+    char * local, * remote, * pipename; int recover, append, xlate, fcs, rcs;
+/* getfile */ {
+    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 (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 (!pipename && (!local || !local[0]))
+      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',(long)pktnum,remote);
+        ftscreen(SCR_AN,0,0L,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 */
+    debug(F111,"ftp recvrequest rc",remote,rc);
+    if (cancelfile || cancelgroup) {
+        debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup);
+        ftscreen(SCR_ST,ST_INT,0l,"");
+    } else if (rc > 0) {
+        debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup);
+        ftscreen(SCR_ST,ST_SKIP,0l,cmarg);
+    } else if (rc < 0) {
+        switch (ftpcode) {
+          case -4:                      /* Network error */
+          case -2:                      /* File error */
+            ftscreen(SCR_ST,ST_MSG,0l,ck_errstr());
+            break;
+          case -3:
+            ftscreen(SCR_ST,ST_MSG,0l,"Failure to make data connection");
+            break;
+          case -1:
+            ftscreen(SCR_ST,ST_INT,0l,""); /* (should be covered above) */
+            break;
+          default:
+            ftscreen(SCR_ST,ST_MSG,0l,&ftp_reply_str[4]);
+        }
+    } else {                            /* Tudo bem */
+        ftscreen(SCR_PT,'Z',0L,"");
+        if (rc == 0) {
+            ftscreen(SCR_ST,ST_OK,0L,""); /* For screen */
+            makestr(&rrfspec,remote);     /* For WHERE command */
+            makestr(&rfspec,fullname);
+        }
+    }
+    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);
+        } 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
+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;
+
+/* putfile */ {
+
+    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 = 0L;
+    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 (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',(long)pktnum,local);
+        ftscreen(SCR_AN,0,0L,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);
+            ftscreen(SCR_ST,ST_SKIP,SKP_DAT,fullname); /* Skip this one */
+            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,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,0l,"");
+    } else if (rc > 0) {
+        debug(F101,"ftp put skipped",local,rc);
+        ftscreen(SCR_ST,ST_SKIP,rc,fullname);
+    } else if (rc < 0) {
+        debug(F111,"ftp put error",local,ftpcode);
+        ftscreen(SCR_ST,ST_MSG,0L,&ftp_reply_str[4]);
+    } else {
+        debug(F111,"ftp put not canceled",ckitoa(displa),fdispla);
+        ftscreen(SCR_PT,'Z',0L,"");
+        debug(F111,"ftp put ST_OK",local,rc);
+        ftscreen(SCR_ST,ST_OK,0L,"");
+        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) {
+            if (rc == SKP_XNX)
+              tlog(F100," /simulate: WOULD BE SENT:","no remote file",0);
+            else if (rc == SKP_XUP)
+              tlog(F100," /simulate: WOULD BE SENT:","remote file older",0);
+            else if (rc == SKP_SIM)
+              tlog(F100," /simulate: WOULD BE SENT","",0);
+            else
+              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,0L,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,0L,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
+ispathsep(c) int c; {
+    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);
+}
+
+/* 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);
+    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',spackets,NULL);
+    }
+    return(rc);
+}
+
+/* c m d l i n p u t  --  Command-line PUT */
+
+int
+cmdlinput(stay) int stay; {
+    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(SCR_TC,0,0L,"");
+
+    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 {                  /* Temporary array for switch values */
+        char * sval;
+        int ival;
+    } pv[SND_MAX+1];
+
+    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 */
+    }
+    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_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:
+            if (!getval) break;
+            if ((x = cmnum("Size in bytes","0",10,&y,xxstring)) < 0)
+              goto xputx;
+            pv[n].ival = 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 && 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) {
+            y = zchki(s);
+            if (y < 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].ival;
+        if (pv[SND_LAR].ival > -1)
+          sndlarger = pv[SND_LAR].ival;
+        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 = 0L;                           /* 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);
+
+        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(SCR_TC,0,0L,"");
+    }
+    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
+cmdlinget(stay) int stay; {
+    int i, 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 = -1L;
+    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 = -1L;
+	if (sizeok) {
+	    x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */
+	    if (x == REPLY_COMPLETE)
+	      fsize = atol(&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 */
+
+        x = zchki(s2);
+        if (x > -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',0L,s);
+                ftscreen(SCR_ST,ST_SKIP,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++;
+            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 > -1L) {		/* 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 = -1L;
+	    if (sizeok) {
+		x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm);
+		if (x == REPLY_COMPLETE)
+		  fsize = atol(&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 */
+
+        x = zchki(s2);
+        if (x > -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',0L,s);
+                ftscreen(SCR_ST,ST_SKIP,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++;
+            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(SCR_TC,0,0L,"");
+    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
+doftpget(cx,who) int cx, who; {         /* who == 1 for ftp, 0 for kermit */
+    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;
+    int matchdot = 0;
+    long getlarger = -1, getsmaller = -1;
+    char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL;
+    char * src = "", * local = "";
+    char * pat = "";
+
+    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 {                  /* Temporary array for switch values */
+        char * sval;
+        int ival;
+    } pv[SND_MAX+1];
+
+    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 = -1L;
+    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 */
+    }
+    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:
+            if (!getval) break;
+            if ((x = cmnum("Size in bytes","0",10,&y,xxstring)) < 0)
+              goto xgetx;
+            pv[n].ival = 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 && 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 */
+
+    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;
+    }
+#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].ival > -1)
+      getsmaller = pv[SND_SMA].ival;
+    if (pv[SND_LAR].ival > -1)
+      getlarger = pv[SND_LAR].ival;
+    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 = 0L;                           /* 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 (!(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 = 0L;                    /* REGET position */
+        cancelfile = 0;                 /* This file not canceled yet */
+        haspath = 0;                    /* Recalculate this each time thru */
+
+        if (getone) {                   /* GET */
+            char * p;
+            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',0L,s);
+                        ftscreen(SCR_ST,ST_MSG,0L,"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 */
+		int 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 = -1L;
+
+	/* 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 > -1L || getlarger > -1L)) {
+	    if (havesize > -1L) {	/* 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 = -1L;
+		if (sizeok) {
+		    x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
+		    if (x == REPLY_COMPLETE) {
+			fsize = atol(&ftp_reply_str[4]);
+			gotsize = 1;
+		    }
+		}
+	    }
+            if (gotsize) {
+                if (getsmaller > -1L && fsize >= getsmaller)
+                  skipthis++;
+                if (getlarger > -1L && 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',0L,s);
+            if (msg)
+              ftscreen(SCR_ST,ST_ERR,0L,msg);
+            else
+              ftscreen(SCR_ST,ST_SKIP,0L,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,0L,"Directory creation failure");
+                    break;
+                }
+            }
+        }
+
+        /* Not skipping */
+
+	selected++;			/* Count this file as selected */
+        pn = NULL;
+
+	if (!gotsize && !mdel) {	/* Didn't get size yet */
+	    if (havesize > -1L) {	/* Already have file size? */
+		fsize = havesize;
+		gotsize = 1;
+	    } else {			/* No - must ask server */
+		fsize = -1L;
+		if (sizeok) {
+		    x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
+		    if (x == REPLY_COMPLETE) {
+			fsize = atol(&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) {
+                x = zchki(s2);
+                debug(F111,"ftp get zchki",s2,x);
+                debug(F111,"ftp get x_fnc",s2,x_fnc);
+
+                if (x > -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,0L,"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 cancelfile",s,cancelfile);
+                debug(F111,"ftp get cancelgroup",s,cancelgroup);
+                debug(F111,"ftp get renaming",s,renaming);
+            }
+#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);
+                } else 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++;
+            if (geterror) {
+                status = 0;
+                ftscreen(SCR_EM,0,0L,"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 (x > -1) {                       /* 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(SCR_TC,0,0L,"");
+#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;
+#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 ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) {
+	do {
+	    reply = getreply(0,lcs,rcs,ftp_vbm,0);
+	} while (reply == REPLY_PRELIM);
+    }
+    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
+doftprmt(cx,who) int cx, who; {         /* who == 1 for ftp, 0 for kermit */
+    /* 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);
+        return(doftpcwd((char *)line,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, n;
+    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[];
+            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 */
+        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,NULL,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
+static char *
+shopl(x) int x; {
+    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)");
+    }
+}
+
+int
+shoftp(brief) {
+    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;
+    }
+    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 .~<number>~.",
+    "  /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 succesfully.",
+    "  /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 .~<number>~.",
+#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_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_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 <name> {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.\n\n");
+        return(0);
+
+#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;
+static int      ptflag = 0;
+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
+ftpcmd(cmd,arg,lcs,rcs,vbm) char * cmd, * arg; int lcs, rcs, vbm; {
+    char * s = NULL;
+    int r = 0, x = 0, fc = 0, len = 0, cmdlen = 0, q = -1;
+    sig_t oldintr;
+
+    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);
+    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
+ftpopen(remote, service, use_tls) char * remote, * service; int use_tls; {
+    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(ftp_port);
+        }
+    } 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;
+
+#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;
+
+    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
+    if (auth_type && !strcmp(auth_type,"TLS")) {
+        ssl_ftp_ctx=SSL_CTX_new(SSLv3_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(ftp_bug_use_ssl_v2 ? SSLv23_client_method() : 
+                                  SSLv3_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,
+                 (char *)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,
+                 (char *)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,(char *)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,(char *)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 && !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
+cmdcancel(sig) int sig; {
+#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
+xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; {
+#ifdef NOCSETS
+    return(c);
+#else
+    static char buf[128];
+    static int cx;
+    int c0, c1;
+
+    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
+parsefeat(s) char * s; {		/* Parse a FEATURE response */
+    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)
+      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 *
+parsefacts(s) char * s; {		/* Parse MLS[DT] File Facts */
+    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 = atol(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
+getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; {
+    /* 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;
+    sig_t oldintr;
+    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", <line with ftpcode == 0>, "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
+cancelsend(sig) int sig; {
+    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
+changetype(newtype, show) int newtype, show; {
+    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, t, 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 != CR) {       /* Bad number */
+                debug(F110,"doftpsend2 bad size",ftp_reply_str,0);
+                sendstart = 0L;
+            } else if (sendstart > fsize) { /* Remote file bigger than local */
+                debug(F110,"doftpsend2 big size",ckltoa(fsize),sendstart);
+                sendstart = 0L;
+            }
+	    /* 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 = 0L;         /* Send the whole file */
+            }
+        }
+        changetype(ftp_typ,0);          /* Change back to appropriate type */
+        if (sendstart > 0L) {           /* Still restarting? */
+            if (sendstart == fsize) {   /* Same size - no need to send */
+                debug(F111,"doftpsend2 /restart SKIP",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 = 0L; */
+        }
+    }
+#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);
+
+    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 */
+        zclose(ZIFILE);
+#ifdef PIPESEND
+        if (sndfilter)
+          pipesend = 0;
+#endif /* PIPESEND */
+        ftpsndret = -1;
+#ifdef NTSIG
+        ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+        return;
+    }
+    dout = dataconn(ftpsnd.lmode);             /* Get data connection */
+    if (dout == -1) {
+        failftpsend2(threadinfo);
+#ifdef NTSIG
+        ckThreadEnd(threadinfo);
+#endif /* NTSIG */
+        return;
+    }
+    /* Initialize per-file stats */
+    ffc = 0L;                           /* Character counter */
+    cps = oldcps = 0L;                  /* Thruput */
+#ifdef GFTIMER
+    rftimer();                          /* reset f.p. timer */
+#endif /* GFTIMER */
+
+#ifdef SIGPIPE
+    ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
+#endif /* SIGPIPE */
+    switch (curtype) {
+      case FTT_BIN:                     /* Binary mode */
+      case FTT_TEN:
+        errno = d = 0;
+        while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
+            ftpsnd.bytes += n;
+            ffc += n;
+            debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
+            hexdump("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',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',spackets,NULL);
+                    }
+                }
+#ifdef CK_SSL
+            }
+#endif /* CK_SSL */
+            if (d <= 0)
+              break;
+        }
+        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
+sendrequest(cmd, local, remote, xlate, incs, outcs, restart)
+    char *cmd, *local, *remote; int xlate, incs, outcs, restart;
+{
+    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 */
+    
+    if (openi(local) == 0)              /* Try to open the input file */
+        return(-1);
+
+    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
+cancelrecv(sig) int sig; {
+    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
+netgetc() {
+    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;
+    long   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);
+    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;
+    long bytes = 0L;
+    int bare_lfs = 0;
+    int blksize = 0;
+    ULONG start = 0L, stop;
+    char * p;
+    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;
+
+    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",ckltoa(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 = NUL; 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 = 0L;                           /* 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;
+        }
+        if (c < 0) {
+            debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
+            if (c == -1 && errno != EPIPE)
+              if ((!dpyactive || ftp_deb))
+                perror("netin");
+            bytes = -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) {
+            int t;
+#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) {
+                    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)
+                          goto break2;
+                        if (c == '\0') {
+                            bytes++;
+                            goto contin2;
+                        }
+                    }
+                }
+                if (c < 0)
+                  break;
+#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++;
+              contin2:
+                ;
+            }
+          break2:
+            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 = -1;
+            }
+            if (c == -2)
+              bytes = -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
+recvrequest(cmd, local, remote, lmode, printnames, recover, pipename,
+            xlate, fcs, rcs)
+    char *cmd, *local, *remote, *lmode, *pipename;
+    int printnames, recover, xlate, fcs, rcs;
+{
+#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 = 0L;
+
+    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 = 0L;		/* Local file size */
+    rs_len = 0L;                        /* 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 != 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;
+    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 */
+            int s;
+#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 != -1) {
+                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((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(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 && !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,0L,"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,0L,"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
+dataconn(lmode) char *lmode; {
+    int s;
+#ifdef IP_TOS
+    int tos;
+#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;
+    sig_t oldintr;
+    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
+cancelpt(sig) int sig; {
+    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; {
+    sig_t oldintr;
+    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
+
+struct {
+    CONST gss_OID_desc * CONST * mech_type;
+    char *service_name;
+} gss_trials[] = {
+    { &gss_mech_krb5, "ftp" },
+    { &gss_mech_krb5, "host" },
+};
+
+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);
+}
+#endif /* FTP_SECURITY */
+
+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);
+}
+
+static VOID
+cancel_remote(din) int din; {
+    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 */
+}
+
+static int
+fts_dpl(x) int x; {
+    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
+fts_cpl(x) int x; {
+    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);
+}
+
+#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 */
+
+static char *
+ftp_hookup(host, port, tls) char * host; int port; int tls; {
+    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 */
+
+#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 != -1) {
+        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 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 && 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
+ftp_login(host) char * host; {          /* (also called from ckuusy.c) */
+    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
+ftp_rename(from, to) char * from, * to; {
+    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
+ftp_umask(mask) char * mask; {
+    int rc;
+    rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE);
+    return(rc);
+}
+
+static int
+ftp_user(user,pass,acct) char * user, * pass, * acct; {
+    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 i, 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 = -1L;			/* 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
+looping_write(fd, buf, len)
+    int fd;
+    register CONST char *buf;
+    int len;
+{
+    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
+looping_read(fd, buf, len)
+    int fd;
+    register char *buf;
+    register int len;
+{
+    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
+secure_putbyte(fd, c) int fd; CHAR c; {
+    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
+secure_flush(fd) int fd; {
+    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',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;
+
+    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
+secure_getbyte(fd,fc) int fd,fc; {
+    /* 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 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);
+            switch (error) {
+              case SSL_ERROR_NONE:
+                nin = bufp = count;
+                rpackets++;
+                pktnum++;
+                if (fdispla != XYFD_B) {
+                    rpktl = count;
+                    ftscreen(SCR_PT,'D',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, 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',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
+ */
+static int
+secure_getc(fd,fc) int fd,fc; {		/* file descriptor, function code */
+    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);
+            nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
+            if (nin <= 0) {
+                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);
+            hexdump("ftp secure_getc recv",ucbuf,16);
+            rpackets++;
+            pktnum++;
+            if (fdispla != XYFD_B) {
+                rpktl = nin;
+                ftscreen(SCR_PT,'D',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
+secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; {
+    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);
+          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
+radix_encode(inbuf, outbuf, inlen, outlen, decode)
+    CHAR inbuf[], outbuf[];
+    int inlen, *outlen, decode;
+{
+    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 *
+radix_error(e) int e;
+{
+    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;
+    sig_t oldintr;
+    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;
+    sig_t oldintr;
+    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; {
+    sig_t oldintr;
+    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; {
+    sig_t oldintr;
+    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) */
diff --git a/ckermit-8.0.211/ckcker.h b/ckermit-8.0.211/ckcker.h
new file mode 100644
index 0000000..b392b89
--- /dev/null
+++ b/ckermit-8.0.211/ckcker.h
@@ -0,0 +1,1418 @@
+/* ckcker.h -- Symbol and macro definitions for C-Kermit */
+
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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
+#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	    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 defined file numbers */
+
+#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 */
+
+/* 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, long) );
+_PROTOTYP( int z_line, (int, long) );
+_PROTOTYP( int z_getmode, (int) );
+_PROTOTYP( int z_getfnum, (int) );
+_PROTOTYP( long z_getpos, (int) );
+_PROTOTYP( long z_getline, (int) );
+_PROTOTYP( long z_count, (int, int) );
+_PROTOTYP( char * z_getname, (int) );
+_PROTOTYP( char * ckferror, (int) );
+#endif /* CKCHANNELIO */
+
+_PROTOTYP( int scanfile, (char *, int *, int) );
+
+/*  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 where memory is */
+#define INBUFSIZE 32768			/* not a problem... */
+#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, long, char *) );
+#ifdef VMS
+#define xxscreen(a,b,c,d) \
+if (local && fdispla != XYFD_N) \
+ckscreen((int)a,(char)b,(long)c,(char *)d)
+#else
+#define xxscreen(a,b,c,d) \
+if (local && !backgrd && fdispla != XYFD_N) \
+ckscreen((int)a,(char)b,(long)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 */
+
+/* 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 */
+
+#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 */
+_PROTOTYP( int ckcgetc, (int) );
+_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, () );
+_PROTOTYP( int sndstring, (char *) );
+_PROTOTYP( VOID ckhost, (char *, int) );
+_PROTOTYP( int gettcs, (int, int) );
+_PROTOTYP( VOID getdialenv, (void) );
+_PROTOTYP( VOID setprefix, (int) );
+_PROTOTYP(VOID initproto,(int,char *,char *,char *,char *,char *,char*,char*));
+_PROTOTYP( VOID initpat, (void) );
+_PROTOTYP( VOID initcsets, (void) );
+_PROTOTYP( char * getsysid, (char *) );
+_PROTOTYP( int getsysix, (char *) );
+#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 *,
+			    long, long,
+			    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 urldata {
+    char * sav;			/* The URL itself */
+    char * svc;			/* Service */
+    char * usr;			/* User */
+    char * psw;			/* Password */
+    char * hos;			/* Host */
+    char * por;			/* Port */
+    char * pth;			/* Path */
+};
+_PROTOTYP(int urlparse, (char *, struct urldata *));
+#endif /* CK_URL */
+
+#endif /* CKCKER_H */
+
+/* End of ckcker.h */
diff --git a/ckermit-8.0.211/ckclib.c b/ckermit-8.0.211/ckclib.c
new file mode 100644
index 0000000..36bf111
--- /dev/null
+++ b/ckermit-8.0.211/ckclib.c
@@ -0,0 +1,2883 @@
+char * cklibv = "C-Kermit library, 8.0.033, 16 Mar 2003";
+
+#define CKCLIB_C
+
+/* C K C L I B . C  --  C-Kermit Library routines. */
+
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1999, 2004,
+    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.
+    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.
+    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.
+
+  Prototypes are in ckclib.h.
+
+  Note: This module should not contain any extern declarations.
+*/
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcasc.h"
+
+/* 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() right-pads dest with NULs if it is longer than src.
+   . 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 an entire string into a buffer without overrun.
+   . 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 = 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 = 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 *
+chartostr(x) int x; {			/* Call with char x */
+    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
+ckrchar(s) char * s; {
+    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 *
+ckstrpbrk(s1, s2) char * s1, * s2; {
+    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
+cklower(s) char *s; {
+    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
+ckupper(s) char *s; {
+    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 */
+/* ckltoa */ {
+    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 I T O A  --  Int to string  -- FOR DISCIPLINED USE ONLY  */
+
+char *
+ckitoa(n) int n; {			/* See comments with ckltoa(). */
+    long nn;
+    nn = n;
+    return(ckltoa(nn));
+}
+
+
+char *					/* Unsigned int to string */
+ckuitoa(n) unsigned int n; {
+    unsigned long nn;
+    nn = n;
+    return(ckultoa(nn));
+}
+
+char *
+ckitox(n) int n; {			/* Int to hex */
+    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
+/* 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
+ckindex(s1,s2,t,r,icase) char *s1, *s2; int t, r, icase; {
+    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);
+	}
+    } 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 *
+ckstrstr(s1, s2) char * s1, * s2; {
+    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 */
+
+char *
+brstrip(p) char *p; {
+    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 *
+fnstrip(p) char *p; {
+    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
+dquote(fn, len, flag) char *fn; int len; int flag; {
+    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
+untabify(s1,s2,max) char * s1, * s2; int max; {
+    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
+makelist(s,list,len) char * s; char *list[]; int len; {
+    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
+ckmemcpy(p,s,n) char *p, *s; int n; {
+    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().
+*/
+int
+ckstrcmp(s1,s2,n,c) char *s1, *s2; register int n, c; {
+    register CHAR t1, t2;
+    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);
+    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);
+	}
+	if (t1 < t2) return(-1);	/* s1 < s2 */
+	if (t1 > t2) return(1);		/* s1 > s2 */
+    }
+    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
+ckstrpre(s1,s2) char *s1, *s2; {
+    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.
+*/
+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;
+
+int
+ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; {
+    int q = 0, i = 0, k = -1, x, flag = 0;
+    int rc = 0;				/* Return code */
+    int where = -1;
+    CHAR cp;				/* Current character from pattern */
+    CHAR cs;				/* Current character from string */
+    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);
+    }
+    if (matchdepth == 0) {		/* Top-level call? */
+	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 */
+		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;
+		}
+	    }
+	    if (!clist[(unsigned)cs]) {	/* Match? */
+		MATCHRETURN(5,0);	/* Nope, done. */
+	    }
+	    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 (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;
+	    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);
+		while (*string && (k = ckmatch(p,string,icase,opts) < 1)) {
+		    string++;
+		    stringpos++;
+		}
+		debug(F111,"CKMATCH *<meta> k",string, k);
+		if (!matchpos && k > 0) {
+		    matchpos = stringpos;
+		    debug(F111,"CKMATCH *<meta>",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[96];
+#endif /* DEBUG */
+	if (matchdepth > 0)
+	  matchdepth--;
+	matchpos = rc;
+#ifdef DEBUG
+	ckmakxmsg(msgbuf,96,
+		  "CKMATCH RETURN[",
+		  ckitoa(where),
+		  "] matchpos=",
+		  ckitoa(matchpos),
+		  " matchdepth=",
+		  ckitoa(matchdepth),
+		  " string=",NULL,NULL,NULL,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
+isfloat(s,flag) char *s; int flag; {
+    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 */
+}
+#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
+sh_sort(s,p,n,k,r,c) char **s, **p; int n, k, r, c; {
+    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 *
+ckradix(s,in,out) char * s; int in, out; {
+    char c, *r = rxresult;
+    int d, minus = 0;
+    unsigned long zz = 0L;
+    long z = 0L;
+    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
+b8tob64(s,n,out,len) char * s,* out; int n, len; {
+    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
+b64tob8(s,n,out,len) char * s,* out; int n, len; { /* Decode */
+    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() */
+/* Allows leading space, sign */
+
+int
+chknum(s) char *s; {			/* Check Numeric String */
+    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
+rdigits(s) char *s; {
+    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[10];
+    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
+lset(p,s,n,c) char *s; char *p; int n; int c; {
+    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
+rset(p,s,n,c) char *s; char *p; int n; int c; {
+    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
+hextoulong(s,n) char *s; int n; {
+    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 = 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.
+
+  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 VOID
+setword(n,s,len) int n, len; char * s; {
+    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 *
+cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; {
+    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 */
+
+    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 < 1) {			/* If 0 (or less) */
+	    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;
+#ifdef COMMENT
+    while (*p++) slen++;		/* Make pokeable copy of s1 */
+    if (!splitbuf || slen > nsplitbuf) { /* Allocate buffer if needed */
+	int xx;
+	if (splitbuf)
+	  free(splitbuf);
+	xx = (slen < 255) ? 255 : xx + (xx / 4);
+	debug(F101,"cksplit splitbuf","",xx);
+	splitbuf = (char *)malloc(xx+1);
+	if (!splitbuf) {		/* Memory allocation failure... */
+	    ck_sval.a_size = -1;
+	    return(&ck_sval);
+	}
+	nsplitbuf = xx;			/* Remember size of buffer */
+    }
+#else
+/*
+  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++)) ;
+    }
+
+#endif /* COMMENT */
+    s = splitbuf;
+    sep = s2;				/* s2 = break set */
+    if (!sep) sep = "";
+    notsep = s3;			/* s3 = include set */
+    if (!notsep) notsep = "";
+    if (n2 < 0) n2 = 63;		/* n2 = grouping mask */
+    grouping = n2;
+    p = "";				/* Pointer to current word */
+    while (c) {				/* Loop through string */
+	c = *s;
+	class = 0;
+	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 (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')
+		     );
+	    }
+	    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;
+			}
+		    }
+		}
+	    }
+	}
+	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];
+		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;
+		}
+		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 */
+		wordnum++;		/* Count it */
+		if (splitting) {	/* Dispose of it appropriately */
+		    if (wordnum > max) {   /* Add to array if splitting */
+			ck_sval.a_size = -2;
+			return(&ck_sval);
+		    }
+		    setword(wordnum,p,len);
+		} else if (wordnum == n) { /* Searching for word n */
+		    setword(1,p,len);
+		    ck_sval.a_size = 1;
+		    return(&ck_sval);
+		}
+		state = ST_BW;		/* Switch to BETWEENWORDS state */
+		len = 0;
+	    }
+	    break;
+
+	  case ST_IG:			/* INGROUP */
+	    if (class & CL_CLS) {	/* Have group closer? */
+		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) {
+			    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);
+			}
+			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) {		/* 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) {
+	    setword(1,p+1,len);
+	    ck_sval.a_size = 1;
+	    return(&ck_sval);
+	}
+    }
+    if (!splitting) {			/* Wanted word n but there was none? */
+	setword(1,NULL,0);
+	ck_sval.a_size = 0;
+	return(&ck_sval);
+    } else {				/* Succeed otherwise */
+	ck_sval.a_size = wordnum;
+	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);
+}
+
+/* End of ckclib.c */
diff --git a/ckermit-8.0.211/ckclib.h b/ckermit-8.0.211/ckclib.h
new file mode 100644
index 0000000..a258664
--- /dev/null
+++ b/ckermit-8.0.211/ckclib.h
@@ -0,0 +1,100 @@
+/* ckclib.h -- C-Kermit library routine prototypes */
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 2002, 2004,
+    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 * ckitox, (int) );
+_PROTOTYP( char * ckltox, (long) );
+_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) );
+
+#endif /* CKCLIB_H */
diff --git a/ckermit-8.0.211/ckcmai.c b/ckermit-8.0.211/ckcmai.c
new file mode 100644
index 0000000..33504dc
--- /dev/null
+++ b/ckermit-8.0.211/ckcmai.c
@@ -0,0 +1,3592 @@
+#define EDITDATE  "10 Apr 2004"		/* Update these with each edit */
+#define EDITNDATE "20040410"		/* Keep them in sync */
+/* Sat Apr 10 12:05:49 2004 */
+
+/*
+  ckcsym.h is used for 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 be before any tests for preprocessor symbols.
+*/
+#include "ckcsym.h"
+/*
+  Consolidated program version information (for UNIX also see ckuver.h).
+  See makever() below for how they are used.
+*/
+/* #ifdef COMMENT */                    /* Uncomment this for test version */
+#ifndef OS2
+#ifndef BETATEST
+#define BETATEST
+#endif /* BETATEST */
+#endif /* OS2 */
+/* #endif */ /* COMMENT */
+
+#ifdef BETATEST
+#ifdef OS2
+#ifdef __DATE__
+#define BETADATE
+#endif /* __DATE__ */
+#endif /* OS2 */
+#endif /* BETATEST */
+
+#ifndef MAC
+/*
+  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.
+*/
+#ifndef BETATEST
+#ifndef OS2                             /* UNIX, VMS, etc... (i.e. C-Kermit) */
+char *ck_s_test = "";			/* "Dev","Alpha","Beta","RC", or "" */
+char *ck_s_tver = "";			/* Test version number or "" */
+#else  /* OS2 */
+char *ck_s_test = "";			/* (i.e. K95) */
+char *ck_s_tver = "";
+#endif /* OS2 */
+#else
+char *ck_s_test = "";			/* Development */
+char *ck_s_tver = "";
+#endif /* BETATEST */
+#else /* MAC */
+char *ck_s_test = "Pre-Alpha";          /* Mac Kermit is always a test... */
+char *ck_s_tver = "";
+#endif /* MAC */
+
+#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 8.0.211";
+#endif /* UNIX */
+
+char *ck_s_ver = "8.0.211";             /* C-Kermit version string */
+long  ck_l_ver =  800211L;              /* C-Kermit version number */
+
+#ifdef OS2
+char *ck_s_xver = "2.2.0";		/* Product-specific version string */
+long  ck_l_xver = 2200L;                /* Product-specific version number */
+#else
+#ifdef MAC
+char *ck_s_xver = "0.995";              /* Product-specific version string */
+long  ck_l_xver = 995L;                 /* Product-specific version number */
+#else
+char *ck_s_xver = "";                   /* Don't touch these... */
+long  ck_l_xver = 0L;                   /* they are computed at runtime */
+#endif /* MAC */
+#endif /* OS2 */
+
+#ifdef OS2
+#ifdef IKSDONLY
+#ifdef NT
+char *ck_s_name = "IKS-NT";
+#else /* NT */
+char *ck_s_name = "IKS-OS/2";
+#endif /* NT */
+#else /* IKSDONLY */
+char *ck_s_name = "Kermit 95";          /* Program name */
+#endif /* IKSDONLY */
+#else
+#ifdef MAC
+char *ck_s_name = "Mac Kermit";
+#else
+char *ck_s_name = "C-Kermit";
+#endif /* MAC */
+#endif /* OS2 */
+
+char *ck_s_who = "";                    /* Where customized, "" = not. */
+char *ck_patch = "";                    /* Patch info, if any. */
+
+#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 */
+#include "ckcdeb.h"                     /* Debug & other symbols */
+
+char * myname = NULL;                   /* The name I am called by */
+#ifndef OS2
+char * exedir = NULL;                   /* Directory I was executed from */
+#endif /* OS2 */
+char * myhome = NULL;			/* Home directory override */
+
+/*  C K C M A I  --  C-Kermit Main program  */
+
+/*
+  Author: Frank da Cruz (fdc@columbia.edu),
+  Columbia University Academic Information Systems, New York City.
+
+COPYRIGHT NOTICE:
+*/
+
+#ifdef OS2
+char *wiksdcpr[] = {
+"Windows Internet Kermit Service Daemon (WIKSD):",
+"Copyright (C) 1985, 2004, Trustees of Columbia University in the City of New",
+"York.  All rights reserved.",
+" ",
+"PERMISSIONS:",
+" ",
+"  The WIKSD software may be obtained directly, in binary form only, from",
+"  the Kermit Project at Columbia University by any individual for his or",
+"  her OWN USE, and by any company or other organization for its own",
+"  INTERNAL DISTRIBUTION and use, including installation on servers that",
+"  are accessed by customers or clients, WITHOUT EXPLICIT LICENSE.  All",
+"  other forms of redistribution must be licensed from the Kermit Project",
+"  at Columbia University.  These permissions apply only to the nonsecure",
+"  version of WIKSD.",
+" ",
+"DISCLAIMER:",
+" ",
+"  THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE",
+"  TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK AS TO ITS",
+"  FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE TRUSTEES OF",
+"  COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK OF ANY KIND, EITHER",
+"  EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED",
+"  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.",
+"  THE TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK SHALL NOT",
+"  BE LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL,",
+"  OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OR IN",
+"  CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS",
+"  HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  YOU SHALL",
+"  INDEMNIFY AND HOLD HARMLESS THE TRUSTEES OF COLUMBIA UNIVERSITY IN",
+"  THE CITY OF NEW YORK, ITS EMPLOYEES AND AGENTS FROM AND AGAINST ANY",
+"  AND ALL CLAIMS, DEMANDS, LOSS, DAMAGE OR EXPENSE (INCLUDING",
+"  ATTORNEYS' FEES) ARISING OUT OF YOUR USE OF THIS SOFTWARE.",
+" ",
+"The above copyright notice, permissions notice, and disclaimer may not be",
+"removed, altered, or obscured and shall be included in all copies of the",
+"WIKSD software.  The Trustees of Columbia University in the City of",
+"New York reserve the right to revoke this permission if any of the terms",
+"of use set forth above are breached.",
+" ",
+"For further information, contact the Kermit Project, Columbia University,",
+"612 West 115th Street, New York NY 10025-7799, USA; Phone +1 (212) 854 3703,",
+"Fax +1 (212) 662 6442, kermit@columbia.edu, http://www.columbia.edu/kermit/",
+""
+};
+#endif /* OS2 */
+
+char *copyright[] = {
+
+#ifdef pdp11
+"Copyright (C) 1985, 2004, Trustees of Columbia University, NYC.",
+"All rights reserved.",
+" ",
+#else
+#ifdef OS2
+"Copyright (C) 1985, 2004, Trustees of Columbia University in the City of New",
+"York.  All rights reserved.  This software is furnished under license",
+"and may not be reproduced without license to do so.  This copyright notice",
+"must not be removed, altered, or obscured.",
+" ",
+"  THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE",
+"  TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK AS TO ITS",
+"  FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE TRUSTEES OF",
+"  COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK OF ANY KIND, EITHER",
+"  EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED",
+"  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.",
+"  THE TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK SHALL NOT",
+"  BE LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL,",
+"  OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OR IN",
+"  CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS",
+"  HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  YOU SHALL",
+"  INDEMNIFY AND HOLD HARMLESS THE TRUSTEES OF COLUMBIA UNIVERSITY IN",
+"  THE CITY OF NEW YORK, ITS EMPLOYEES AND AGENTS FROM AND AGAINST ANY",
+"  AND ALL CLAIMS, DEMANDS, LOSS, DAMAGE OR EXPENSE (INCLUDING",
+"  ATTORNEYS' FEES) ARISING OUT OF YOUR USE OF THIS SOFTWARE.",
+" ",
+#else
+"Copyright (C) 1985, 2004,",
+"  The Trustees of Columbia University in the City of New York.",
+"  All rights reserved.",
+" ",
+"PERMISSIONS:",
+" ",
+"The C-Kermit software may be obtained directly from the Kermit Project at",
+"Columbia University (or from any source explicitly licensed by the Kermit",
+"Project or implicitly licensed by Clause (A) below) by any individual for",
+"his or her OWN USE, and by any company or other organization for its own",
+"INTERNAL DISTRIBUTION and use, including installation on servers that are",
+"accessed by customers or clients, WITHOUT EXPLICIT LICENSE.",
+" ",
+"Conditions for REDISTRIBUTION are as follows:",
+" ",
+"(A) The C-Kermit software, in source and/or binary form, may be",
+"    included WITHOUT EXPLICIT LICENSE in distributions of OPERATING",
+"    SYSTEMS that have OSI (Open Source Initiative, www.opensource.org)",
+"    approved licenses, even if non-Open-Source applications (but not",
+"    operating systems) are included in the same distribution.  Such",
+"    distributions include, but are not limited to, CD-ROM, FTP site,",
+"    Web site, or preinstalled software on a new GENERAL-PURPOSE",
+"    computer, as long as the primary character of the distribution is",
+"    an Open Source operating system with accompanying utilities.  The",
+"    C-Kermit source code may not be changed without the consent of the",
+"    Kermit Project, which will not be unreasonably withheld (this is",
+"    simply a matter of keeping a consistent and supportable code base).",
+" ",
+"(B) Inclusion of C-Kermit software in whole or in part, in any form, in",
+"    or with any product not covered by Clause (A), or its distribution",
+"    by any commercial enterprise to its actual or potential customers",
+"    or clients except as in Clause (A), requires a license from the",
+"    Kermit Project, Columbia University; contact kermit@columbia.edu.",
+" ",
+"The name of Columbia University may not be used to endorse or promote",
+"products derived from or including the C-Kermit software without specific",
+"prior written permission.",
+" ",
+"DISCLAIMER:",
+" ",
+"  THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE",
+"  TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK AS TO ITS",
+"  FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE TRUSTEES OF",
+"  COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK OF ANY KIND, EITHER",
+"  EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED",
+"  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.",
+"  THE TRUSTEES OF COLUMBIA UNIVERSITY IN THE CITY OF NEW YORK SHALL NOT",
+"  BE LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL,",
+"  OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR",
+"  IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS",
+"  HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  YOU SHALL",
+"  INDEMNIFY AND HOLD HARMLESS THE TRUSTEES OF COLUMBIA UNIVERSITY IN",
+"  THE CITY OF NEW YORK, ITS EMPLOYEES AND AGENTS FROM AND AGAINST ANY",
+"  AND ALL CLAIMS, DEMANDS, LOSS, DAMAGE OR EXPENSE (INCLUDING",
+"  ATTORNEYS' FEES) ARISING OUT OF YOUR USE OF THIS SOFTWARE.",
+" ",
+"The above copyright notice, permissions notice, and disclaimer may not be",
+"removed, altered, or obscured and shall be included in all copies of the",
+"C-Kermit software.  The Trustees of Columbia University in the City of",
+"New York reserve the right to revoke this permission if any of the terms",
+"of use set forth above are breached.",
+#endif /* OS2 */
+#endif /* pdp11 */
+
+#ifdef OS2
+"Portions Copyright (C) 1995, Oy Online Solutions Ltd., Jyvaskyla, Finland.",
+#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 <eay@cryptosoft.com>.",
+#endif /* CK_ENCRYPTION */
+#ifdef CK_SRP
+"Portions Copyright (C) 1997, Stanford University.",
+#endif /* CK_SRP */
+#endif /* CK_AUTHENTICATION */
+
+#ifndef pdp11
+" ",
+"For further information, contact the Kermit Project, Columbia University,",
+"612 West 115th Street, New York NY 10025-7799, USA; phone +1 (212) 854 3703,",
+"fax +1 (212) 663 8202 or +1 (212) 662 6442, email kermit@columbia.edu,",
+"Web http://www.columbia.edu/kermit/ or http://www.kermit-project.org/.",
+#endif /* pdp11 */
+""};
+
+/*
+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.
+  Order from Digital Press:    +1 (800) 366-2665
+  Or from Columbia University: +1 (212) 854-3703
+
+For Kermit 95, also:
+
+  "Kermit 95" by Christine M. Gianone and Frank da Cruz,
+  Manning Publications, Greenwich CT, USA (1998) - Online.
+
+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).  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, 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
+   Nelson Beebe, U of Utah
+   Gerry Belanger, Cognitronics
+   Karl Berry, UMB
+   Mark Berryman, SAIC
+   Dean W Bettinger, SUNY
+   Gary Bilkus
+   Peter Binderup, Denmark
+   David Bolen, Advanced Networks and Services, Inc.
+   Marc Boucher, U of Montreal
+   Charles Brooks, EDN
+   Bob Brown
+   Mike Brown, Purdue U
+   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
+   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
+   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
+   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
+   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
+   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
+   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
+   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
+   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)
+   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)
+   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
+   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
+   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
+   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)
+   APPP Scorer, Leeds Polytechnic, UK
+   Gordon Scott, Micro Focus, Newbury UK
+   Gisbert W. Selke, WIdO, Bonn, Germany
+   David Singer, IBM Almaden Research Labs
+   David Sizeland, U of London Medical School
+   Fridrik Skulason, Iceland
+   Rick Sladkey (Linux)
+   Dave Slate
+   Bradley Smith, UCLA
+   Fred Smith, Merk / Computrition
+   Richard S Smith, Cal State
+   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
+   Glen Thobe
+   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
+   Dimitri Vulis, CUNY
+   Roger Wallace, Raytheon
+   Stephen Walton, Calif State U, Northridge (Amiga)
+   Jamie Watson, Adasoft, Switzerland (AIX)
+   Rick Watson, U of Texas (Macintosh)
+   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)
+   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 */
+
+#ifndef NOSPL
+#include "ckuusr.h"
+#endif /* NOSPL */
+
+#ifdef OS2ONLY
+#define INCL_VIO                        /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#endif /* OS2ONLY */
+
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#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 */
+    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 */
+    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 */
+
+#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 */
+
+int nzxopts = 0;                        /* Options for nzxpand() */
+int nfils = 0;                          /* Number of files in file group */
+long fsize = 0L;                        /* Size of current file */
+#ifdef UNIX
+int wildxpand = 0;                      /* Who expands wildcards */
+#else /* UNIX */
+#ifdef STRATUS
+int wildxpand = 1;
+#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 */
+
+long filcnt,                    /* Number of files in transaction */
+    filrej,                     /* Number of files rejected in transaction */
+    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 */
+    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 */
+    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? */
+
+/* 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;
+
+long sendstart = 0L;                    /* SEND start position */
+long calibrate = 0L;                    /* Nonzero if calibration run */
+
+#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 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() below. */
+char zinbuffer[INBUFSIZE], zoutbuffer[OBUFSIZE];
+#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 <signal.h>
+
+#ifndef NOCCTRAP
+#include <setjmp.h>
+#include "ckcsig.h"
+ckjmpbuf cmjbuf;
+#ifdef GEMDOS                           /* Special for Atari ST */
+cc_clean();                             /* This can't be right? */
+#endif /* GEMDOS */
+#endif /* NOCCTRAP */
+
+#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", "Windows-32",   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 *
+getsysid(s) char * s; {                 /* Get system-type name */
+    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
+getsysix(s) char *s; {                  /* 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... */
+int
+isabsolute(path) char * path; {
+    int rc = 0;
+    int x;
+    if (!path)
+      return(0);
+    if (!*path)
+      return(0);
+    x = (int) strlen(path);
+    debug(F111,"isabsolute",path,x);
+#ifdef VMS
+    rc = 0;
+    x = ckindex("[",path,0,0,0);        /* 1-based */
+    if (!x)
+       x = ckindex("<",path,0,0,0);
+    debug(F111,"isabsolute left bracket",path,x);
+    if (!x) {
+        x = ckindex(":",path,-1,1,1);
+        if (x)
+          debug(F111,"isabsolute logical",path,x);
+    }
+    if (x > 0)
+      if (path[x] != '.')               /* 0-based */
+        rc = 1;
+#else
+#ifdef UNIX
+    if (*path == '/'
+#ifdef DTILDE
+        || *path == '~'
+#endif /* DTILDE */
+        )
+      rc = 1;
+#else
+#ifdef OS2
+    if (*path == '/' || *path == '\\')
+      rc = 1;
+    else if (isalpha(*path) && x > 2)
+      if (*(path+1) == ':' && (*(path +2) == '/' || *(path+2) == '\\'))
+        rc = 1;
+#else
+#ifdef AMIGA
+    if (*path == '/'
+#ifdef DTILDE
+        || *path == '~'
+#endif /* DTILDE */
+        )
+      rc = 1;
+#else
+#ifdef OSK
+    if (*path == '/'
+#ifdef DTILDE
+        || *path == '~'
+#endif /* DTILDE */
+        )
+      rc = 1;
+#else
+#ifdef datageneral
+    if (*path == ':')
+      rc = 1;
+#else
+#ifdef MAC
+    rc = 0;                             /* Fill in later... */
+#else
+#ifdef STRATUS
+    rc = 0;                             /* Fill in later... */
+#else
+#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 */
+#endif /* VMS */
+    debug(F101,"isabsolute rc","",rc);
+    return(rc);
+}
+
+/*  See if I have direct access to the keyboard  */
+
+int
+is_a_tty(n) int n; {
+#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
+VOID
+initxlist() {
+    extern char * sndexcept[], * rcvexcept[];
+    int i;
+    for (i = 0; i < NSNDEXCEPT; i++) {
+	sndexcept[i] = NULL;
+	rcvexcept[i] = NULL;
+    }
+}
+#endif /* NOXFER */
+
+/* Initialize flow control table */
+
+VOID
+initflow() {                            /* 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
+initproto(y, upbstr, uptstr, srvstr, sndbstr, sndtstr, rcvbstr, rcvtstr)
+    int y;
+    char * upbstr, * uptstr, * srvstr, * sndbstr, * sndtstr, * rcvbstr,
+    * rcvtstr;
+/* 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;
+}
+
+void
+ikslogin() {
+    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 NETCONN
+        clienthost = ckgetpeer();       /* Get client's hostname */
+        debug(F110,"ikslogin clienthost",clienthost,0);
+#endif /* NETCONN */
+        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_exit" */
+            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 */
+    if (inserver)
+        srvidl = timelimit = iks_timo;  /* Set idle limits for IKS */
+#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 */
+    if (!cfilef) {
+        conoll("Interrupt 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 */
+            }
+        }
+        debug(F100,"doicp calling herald","",0);
+        herald();
+    }
+#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);                     /* execute it */
+    while (tlevel > -1) {               /* until it runs out. */
+        sstate = parser(1);             /* Loop getting commands. */
+        if (sstate) proto();            /* Enter protocol if requested. */
+#ifdef NTSIG
+        ck_ih();
+#endif /* NTSIG */
+    }
+    cfilef = 1;                         /* Remember we did this */
+
+#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 */
+    if (!cfilef) {
+        conoll("Interrupt during initialization or command-line processing.");
+        conoll("C-Kermit quitting...");
+    }
+    doexit(BAD_EXIT,-1);                /* Exit with bad status. */
+}
+#endif /* NOICP */
+
+#ifndef NOXFER
+VOID
+setprefix(z) int z; {                   /* Initial control-char prefixing */
+#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[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[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 */
+
+VOID
+makever() {                             /* Make version string from pieces */
+    int x, y;
+#ifndef OS2
+#ifndef MAC
+    ck_s_xver = ck_s_ver;               /* Fill in C-Kermit version number */
+    ck_l_xver = ck_l_ver;               /* for UNIX, VMS, etc. */
+#endif /* MAC */
+#endif /* OS2 */
+    x = strlen(ck_s_name);
+    y = strlen(ck_s_xver);
+    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,"Kermit version",versio,0);
+}
+
+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 NOCMDL
+#ifndef NOURL
+VOID
+dourl() {
+    int rc = 0;
+    char * port = NULL;
+    extern int ttnproto;
+    extern struct urldata g_url;
+
+#ifdef COMMENT
+    /* NOTE: debug() doesn't work yet - 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 /* NOCMDL */
+#endif /* NETCONN */
+#endif /* NOURL */
+
+/*
+  main()...
+
+  If you get complaints about "main: return type is not blah",
+  define MAINTYPE on the CC command line, e.g. "CFLAGS=-DMAINTYPE=blah"
+  (where "blah" is int, long, or whatever).
+
+  If the complaint is "Attempt to return a value from a function of type void"
+  then add -DMAINISVOID.
+*/
+#ifndef MAINTYPE
+#ifndef MAINISVOID
+#define MAINTYPE int
+#endif /* MAINISVOID */
+#endif /* MAINTYPE */
+
+#ifdef MAINISVOID
+#ifndef MAINTYPE
+#define MAINTYPE void
+#endif /* MAINTYPE */
+#endif /* MAINISVOID */
+
+#ifdef aegis
+/* On the Apollo, intercept main to insert a cleanup handler */
+int
+ckcmai(argc,argv) int argc; char **argv;
+#else
+#ifdef MAC                              /* Macintosh */
+int
+main (void)
+#else
+#ifdef __GNUC__                         /* GCC compiler */
+int
+main(argc,argv) int argc; char **argv;
+#else
+#ifdef __DECC                           /* DEC Alpha with DEC C compiler */
+#ifdef __ALPHA
+int
+main(argc,argv) int argc; char **argv;
+#else                                   /* DEC C compiler, not Alpha */
+#define MAINISVOID
+VOID
+main(argc,argv) int argc; char **argv;
+#endif  /* __ALPHA */
+#else
+#ifdef STRATUS                          /* Stratus VOS */
+int
+main(argc,argv) int argc; char **argv;
+#else                                   /* K-95 */
+#ifdef OS2
+#ifdef KUI
+#define MAINISVOID
+void
+Main( int argc, char ** argv )
+#else /* KUI */
+#define MAINISVOID
+VOID
+main(argc,argv) int argc; char **argv;
+#endif /* KUI */
+#else  /* Not K95 */
+MAINTYPE                                /* All others... */
+main(argc,argv) int argc; char **argv;
+#endif /* OS2 */
+#endif /* STRATUS */
+#endif /* __DECC */
+#endif /* __GNUC__ */
+#endif /* MAC */
+#endif /* aegis */
+
+/* main */ {
+
+    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 */
+
+/* Do some initialization */
+
+#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 NOSETKEY                        /* Allocate & initialize the keymap */
+    /* This code has been 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 (sysinit() < 0)                  /* System-dependent initialization. */
+      fatal("Can't initialize!");
+    else
+      initflg = 1;                      /* Remember we did. */
+    debug(F111,"ckcmai myname",myname,howcalled);
+
+#ifdef UNIX
+    getexedir();                        /* Compute exedir variable */
+#endif /* UNIX */
+
+#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 NOICP
+#ifdef CKFLOAT
+    initfloat();                        /* Deduce floating-point precision */
+#endif /* CKFLOAT */
+#endif /* NOICP */
+
+#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() */
+#ifndef VMS
+	/* time.h and MultiNet do not get along */
+        c = time(NULL);
+#endif /* VMS */
+        c *= getpid();
+	/* 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 NOICP
+    if (sstelnet
+#ifdef IKSD
+        || inserver
+#endif /* IKSD */
+        ) {
+        int on = 1, x = 0;
+        extern int ckxech, ttnet, ttnproto, cmdmsk;
+#ifdef SO_SNDBUF
+        extern int tcp_sendbuf;
+#endif
+#ifdef SO_RCVBUF
+        extern int tcp_recvbuf;
+#endif
+#ifdef SO_KEEPALIVE
+        extern int tcp_keepalive;
+#endif
+#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
+        on = 1;
+        x = socket_ioctl(0,FIONBIO,&on);
+        debug(F101,"main FIONBIO","",x);
+#endif /* NON_BLOCK_IO */
+#ifdef SO_OOBINLINE
+        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_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 */
+    }
+    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
+    ikslogin();                          /* IKSD Login and other stuff */
+#ifdef IKSD
+#ifdef NT
+    if ( inserver )
+      setntcreds();
+#endif /* NT */
+#endif /* IKSD */
+#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);
+
+#ifdef NOCCTRAP
+    dotakeini(0);
+#else /* NOCCTRAP */
+    debug(F100,"main about to cc_execute","",0);
+    setint();
+    cc_execute( ckjaddr(cmjbuf), dotakeini, failtakeini );
+#endif /* NOCCTRAP */
+
+    debug(F111,"main 2 cfilef",cmdfil,cfilef);
+    if (cmdfil[0]) {                    /* If we got one (see prescan())... */
+#ifdef NOCCTRAP
+        docmdfile(0);                   /* execute it. */
+#else /* NOCCTRAP */
+        setint();
+        cc_execute( ckjaddr(cmjbuf), docmdfile, failcmdfile );
+#endif /* NOCCTRAP */
+    }
+#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
+#ifndef NOURL
+        if (haveurl) {                  /* Was a URL given? */
+            dourl();                    /* if so, do it. */
+        }
+#endif /* NOURL */
+#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 */
+/*
+  If no action requested on command line, or if -S ("stay") was included,
+  enter the interactive command parser.
+*/
+    if (!clcmds)
+      herald();                         /* Display program herald. */
+
+#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 */
+
+char *zinbuffer = NULL, *zoutbuffer = NULL;
+
+int
+getiobs() {
+    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 */
diff --git a/ckermit-8.0.211/ckcmdb.c b/ckermit-8.0.211/ckcmdb.c
new file mode 100644
index 0000000..de5cebc
--- /dev/null
+++ b/ckermit-8.0.211/ckcmdb.c
@@ -0,0 +1,387 @@
+/*
+  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 <stdio.h>
+#include "ckcdeb.h"
+
+#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 */
diff --git a/ckermit-8.0.211/ckcnet.c b/ckermit-8.0.211/ckcnet.c
new file mode 100644
index 0000000..3bae53e
--- /dev/null
+++ b/ckermit-8.0.211/ckcnet.c
@@ -0,0 +1,14205 @@
+char *cknetv = "Network support, 8.0.283, 7 Feb 2004";
+
+/*  C K C N E T  --  Network support  */
+
+/*
+  Copyright (C) 1985, 2004,
+    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.
+
+  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 <tjh@cryptosoft.com> +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).
+  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.
+    Stephen Riehm added support for IBM AIX X.25 in April 1998.
+  Other contributions as indicated in the code.
+*/
+#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 <errno.h>                      /* this version, but after in others */
+#endif /* I386IX */
+#include "ckcnet.h"                     /* which includes ckctel.h */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+#ifdef CK_DNS_SRV
+#ifdef OS2
+#ifdef NT
+#include <wshelper.h>
+#else /* NT */
+/* !Error OS/2 does not support DNS Service Records. */
+#endif /* NT */
+#else /* OS2 */
+#include <arpa/inet.h>
+#ifdef USE_NAMESER_COMPAT
+#include <arpa/nameser_compat.h>
+#endif	/* USE_NAMESER_COMPAT */
+#include <arpa/nameser.h>
+#include <resolv.h>
+#ifndef PS2AIX10
+#ifndef BSD4
+#ifndef I386IX
+#ifndef RTAIX
+#include <netdb.h>
+#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,
+  ttyfd, quiet, msgflg, what, nettype, ttmdm;
+#ifdef IKSD
+extern int inserver;
+#endif /* IKSD */
+
+char myipaddr[20] = { '\0' };           /* Global copy of my IP address */
+
+#ifdef NETCONN
+/* Don't need any of this if there is no network support. */
+
+/*
+  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 <time.h>
+#include <inet.h>
+#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 */
+#include <arpa/inet.h>                  /* For inet_ntoa() prototype */
+#endif /* HPUX7 */
+#endif /* HPUX */
+
+#ifdef CMU_TCPIP
+#include <time.h>
+#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 <setjmp.h>
+#include <signal.h>
+#include <sys/time.h>
+/*
+  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 I386IX
+#include <errno.h>                      /* Already included above */
+#endif /* I386IX */
+
+#include <signal.h>                     /* Everybody needs this */
+
+#ifdef ZILOG                            /* Zilog has different name for this */
+#include <setret.h>
+#else
+#include <setjmp.h>
+#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
+#include <os2.h>
+#undef COMMENT
+#endif /* NT */
+#include "ckocon.h"
+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
+extern int winsock_version;
+#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";
+    hexdump(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";
+    hexdump(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. */
+        int 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 */
+              hexdump("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.
+*/
+
+/*  N E T O P N  --  Open a network connection.  */
+/*
+  Call with:
+    name of host (or host:service),
+    lcl - local-mode flag to be set if this function succeeds,
+    network type - value defined in ckunet.h.
+*/
+#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; i<cnt; i++) {
+            hosts[next].h_aliases[i] = NULL;
+            makestr(&hosts[next].h_aliases[i],h->h_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; i<cnt; i++) {
+            hosts[next].h_addr_list[i] = malloc(h->h_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 */
+
+#ifndef __DECC                          /* VAXC or GCC */
+
+#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 /* __DECC */
+#endif /* DEC_TCPIP */
+#endif /* EXCELAN */
+#endif /* TCPSOCKET */
+
+#ifndef NOTCPOPTS
+#ifndef datageneral
+int
+ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
+/*
+  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
+sendbuf(sock,size) int sock; int size; {
+/*
+  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
+recvbuf(sock,size) int sock; int size; {
+/*
+  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
+keepalive(sock,onoff) int sock; int onoff; {
+#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
+dontroute(sock,onoff) int sock; int onoff; {
+#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
+no_delay(sock,onoff)  int sock; int onoff; {
+#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 <time.h>
+#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 <sys/time.h>
+#endif /* hp9000s500 */
+#endif /* datageneral */
+#endif /* BELLV10 */
+#endif /* VMS */
+#ifdef SELECT_H
+#include <sys/select.h>
+#endif /* SELECT_H */
+#endif /* BSDSELECT */
+
+#ifdef SELECT
+#ifdef CK_SCOV5
+#include <sys/select.h>
+#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. */
+    if (ttnproto != NP_TCPRAW)
+      ttnproto = NP_NONE;               /* No protocol selected yet. */
+    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. */
+    if (ttnproto != NP_TCPRAW)
+        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
+tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
+    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. */
+#ifdef COMMENT
+    /* Don't do this. */
+    if (ttnproto != NP_TCPRAW)
+      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
+                       (fd_set *)
+#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) {
+            if (ttnproto != NP_TCPRAW)  /* Yes and if raw port not requested */
+              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);
+                strncat(name,":",80-strlen(name));
+                strncat(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 *
+ckname2addr(name) char * name;
+{
+#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 *
+ckaddr2name(addr) char * addr;
+{
+#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 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
+    static unsigned int saddrlen;
+#else
+    static int saddrlen;
+#endif /* VMS */
+#endif /* UNIXWARE */
+#endif /* AIX42 */
+#endif /* PTX */
+    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 */
+}
+
+/* Get fully qualified IP hostname */
+
+#ifndef NONET
+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 <netdb.h> */
+        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 */
+#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","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)
+      strncat(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;
+          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:
+            ttnproto = NP_SSL;
+            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;
+static struct servent *
+ckgetservice(hostname, servicename, ip, iplen)
+    char *hostname; char * servicename; char * ip; int iplen;
+{
+    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;i<dns_naddrs;i++ ) {
+                sin = (struct sockaddr_in *) &dns_addrs[i];
+                printf("dns_addrs[%d] = %s %d\r\n", i,
+                        (char *)inet_ntoa(sin->sin_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);
+}
+
+/*  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.
+*/
+
+int
+netopen(name, lcl, nett) char *name; int *lcl, nett; {
+    char *p;
+    int i, x, dns = 0;
+#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 */
+#ifndef datageneral
+    iax = (unsigned int) inet_addr(namecopy);
+#else
+    iax = -1L;
+#endif /* datageneral */
+    debug(F111,"netopen inet_addr",namecopy,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 < 0
+#endif /* INADDR_NONE */
+        ) {
+        if (!quiet) {
+            printf(" DNS Lookup... ");
+            fflush(stdout);
+        }
+        if ((host = gethostbyname(namecopy)) != NULL) {
+            debug(F100,"netopen 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]
+#ifndef NOHTTP
+                 && (tcp_http_proxy == NULL)
+#endif /* NOHTTP */
+                 ) {                   /* Copying into our argument? */
+                ckstrncpy(name,host->h_name,80);  /* Bad Bad Bad */
+                if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
+                    strncat(name,":",80-strlen(name));
+                    strncat(name,svcbuf,80-strlen(name));
+                }
+            }
+
+#ifdef HADDRLIST
+#ifdef h_addr
+            /* This is for trying multiple IP addresses - see <netdb.h> */
+            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 */
+#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);
+            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,"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 */
+        if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE)
+          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 <arpa/inet.h> 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) ) {
+                    strncat(name,":",80-strlen(name));
+                    strncat(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);
+
+    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
+_PROTOTYP(VOID slrestor,(VOID));
+#ifdef CK_SSL
+int tls_norestore = 0;
+#endif /* CK_SSL */
+#endif /* NOLOCAL */
+
+int
+netclos() {
+    static int close_in_progress = 0;
+    int x = 0, y, z;
+    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) ) {
+		/* 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);
+}
+
+#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;
+    long y;
+    char c;
+    int rc;
+#ifdef NT
+    extern int ionoblock;               /* For Overlapped I/O */
+#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 */
+                     &count
+                     ) < 0) {
+        debug(F101,"nettchk socket_ioctl error","",socket_errno);
+        /* If the connection is gone, the connection is gone. */
+        netclos();
+#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);
+    }
+    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<CR>, or SET LINE<CR>.  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 */
+        y = 1;                          /* Turn on nonblocking reads */
+        z = socket_ioctl(ttyfd,FIONBIO,&y);
+        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 */
+		  y = 0;                          /* Turn off nonblocking reads */
+		  z = socket_ioctl(ttyfd,FIONBIO,&y);
+		  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 */
+        y = 0;                          /* Turn off nonblocking reads */
+        z = socket_ioctl(ttyfd,FIONBIO,&y);
+        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[] */
+            hexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
+            ttibn += x;
+#else /* OS2 */
+#ifdef CK_SSL
+	    if ( ssl_active_flag || tls_active_flag ) {
+		hexdump("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
+nettout(i) int i; {                     /* Catch the alarm interrupts */
+    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
+netxin(n,buf) int n; CHAR * buf; {
+    int len, i, j;
+#ifdef TCPIPLIB
+    int rc;
+#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,buf,n,0)) < 0)
+          return(-1);
+        else
+          return(len);
+    }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+    if (ttnproto == NP_K5U2U) {
+        if ((len = krb5_u2u_read(ttyfd,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
+netinc(timo) int timo; {
+#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,
+#ifndef __DECC
+                            (fd_set *)
+#endif /* __DECC */
+                            &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);
+#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 */
+                    hexdump("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
+nettol(s,n) CHAR *s; int n; {
+#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
+    hexdump("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
+netgetc(int timo)                       /* Input function to point to... */
+#else  /* CK_ANSIC */
+netgetc(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,netgetc);
+                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,netgetc);
+                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 */
+#endif /* NONET */
+
+/* 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
+getlocalipaddr() {
+#ifndef datageneral
+    struct sockaddr_in l_sa;
+    struct sockaddr_in r_sa;
+    GSOCKNAME_T slen = sizeof(struct sockaddr_in);
+    int sock;
+    int rc;
+    struct in_addr laddr;
+
+    /* if still not resolved, then try second strategy */
+    /* This second strategy does not work on Windows */
+
+    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
+getlocalipaddrs(buf,bufsz,index)
+    char * buf;
+    int    bufsz;
+    int    index;
+/* getlocalipaddrs */ {
+#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 */
+
+    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 */
+int
+rlog_naws() {
+    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);
+}
+
+#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
+    {
+        char localuid[UIDBUFLEN+1];
+        ckstrncpy((char *)localuser,(char *)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 
+rlog_ctrl(cp, n)
+     unsigned char *cp;
+     int n;
+{
+    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
+rlog_oob(oobdata, count) CHAR * oobdata; int count; {
+    int i;
+    int flush = 0;
+
+    debug(F111,"rlogin out_of_band","count",count);
+
+    for (i = 0; i<count; i++)   {
+        debug(F101,"rlogin out_of_band","",oobdata[i]);
+                if (oobdata[i] & 0x01)
+                        continue;
+
+        if (oobdata[i] & 0x02) { /* Flush Buffered Data not yet displayed */
+            debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
+
+            /* Only flush the data if in fact we are in a mode that won't */
+            /* get out of sync.  Ie, not when we are in protocol mode.    */
+            switch ( what ) {
+            case W_NOTHING:
+            case W_CONNECT:
+            case W_COMMAND:
+                if ( rlog_inband )
+                    flush = 1;
+                else
+                    ttflui();
+                break;
+            }
+        }
+        if (oobdata[i] & 0x10) {        /* Switch to RAW mode */
+            debug(F101,"rlogin Raw Mode command","",oobdata[i]);
+            rlog_mode = RL_RAW;
+        }
+
+        if (oobdata[i] & 0x20) {        /* Switch to COOKED mode */
+            debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
+            rlog_mode = RL_COOKED;
+        }
+        if (oobdata[i] & 0x80)
+        {        /* Send Window Size Info */
+            debug(F101,"rlogin Window Size command","",oobdata[i]);
+            /* Remember to send WS Info when Window Size changes */
+            if ( !TELOPT_ME(TELOPT_NAWS) ) {
+                TELOPT_ME(TELOPT_NAWS) = 1;
+                rlog_naws();
+            }
+        }
+    }
+    return(flush);
+}
+#ifndef TCPIPLIB
+static SIGTYP
+rlogoobh(sig) int sig; {
+#ifdef SOLARIS
+    char                                /* Or should it be char for all? */
+#else
+    CHAR
+#endif /* SOLARIS */
+      oobdata;
+
+    /* int  count = 0; */ /* (not used) */
+
+    while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
+      /*
+       * We need to do some special processing here.
+       * Just in case the socket is blocked for input
+       *
+       */
+        switch (errno) {
+          case EWOULDBLOCK:
+            break;
+          default:
+            return;
+        }
+    }
+    debug(F101,"rlogin out_of_band","",oobdata);
+    if (oobdata == 0x02) {      /* Flush Buffered Data not yet displayed */
+        debug(F101,"rlogin Flush Buffered Data command","",oobdata);
+        netflui();
+    }
+    if (oobdata & 0x10) {               /* Switch to raw mode */
+        debug(F101,"rlogin Raw Mode command","",oobdata);
+        rlog_mode = RL_RAW;
+    }
+    if (oobdata & 0x20) {               /* Switch to cooked mode */
+        debug(F101,"rlogin Cooked Mode command","",oobdata);
+        rlog_mode = RL_COOKED;
+    }
+    if (oobdata & 0x80) {                 /* Send Window Size Info */
+        debug(F101,"rlogin Window Size command","",oobdata);
+        /* Remember to send WS Info when Window Size changes */
+        if ( !TELOPT_ME(TELOPT_NAWS) ) {
+            TELOPT_ME(TELOPT_NAWS) = 1;
+            rlog_naws();
+        }
+    }
+}
+#endif /* TCPIPLIB */
+#endif /* RLOGCODE */
+
+/* Send network BREAK */
+/*
+  Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
+*/
+int
+netbreak() {
+    CHAR buf[3];
+    if (ttnet == NET_TCPB) {
+        if (ttnproto == NP_TELNET) {
+#ifdef TNCODE
+            buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
+            if (
+#ifdef OS2
+                nettol((char *) buf, 2)
+#else
+                ttol(buf, 2)
+#endif /* OS2 */
+                < 2)
+              return(-1);
+            if (tn_deb || debses || deblog) {
+                extern char tn_msg[];
+                ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(BREAK),
+                          NULL,NULL);
+                debug(F101,tn_msg,"",BREAK);
+                if (debses || tn_deb) tn_debug(tn_msg);
+            }
+            return(1);
+#else
+            debug(F100,"netbreak no TNCODE","",0);
+            return(0);
+#endif /* TNCODE */
+        }
+        /* Insert other TCP/IP protocols here */
+    }
+    /* Insert other networks here */
+    return(0);
+}
+#endif /* NETCONN */
+
+
+#ifdef NETCONN
+#ifdef SUNX25
+/*
+  SunLink X.25 support by Marcello Frutig, Catholic University,
+  Rio de Janeiro, Brazil, 1990.
+*/
+
+/* PAD X.3, X.28 and X.29 support */
+
+static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
+
+/* Initialize PAD */
+
+extern CHAR padparms[];
+
+VOID
+initpad() {
+  padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
+  padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
+  padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
+  padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
+  padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
+  padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
+  padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
+  padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
+  padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
+  padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
+  padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
+  padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
+  padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
+  padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
+  padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
+  padparms[PAD_EDITING]                = 1;  /* can edit */
+  padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
+  padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
+  padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
+}
+
+/* Set PAD parameters */
+
+VOID
+setpad(s,n) CHAR *s; int n; {
+    int i;
+    CHAR *ps = s;
+
+    if (n < 1) {
+        initpad();
+    } else {
+        for (i = 0; i < n; i++) {
+            if (*ps > 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 <time.h>
+#endif /* TIMEH */
+#endif /* NOTIMEH */
+
+#ifndef NOSYSTIMEH
+#ifdef SYSTIMEH
+#include <sys/time.h>
+#endif /* SYSTIMEH */
+#endif /* NOSYSTIMEH */
+
+#ifndef NOSYSTIMEBH
+#ifdef SYSTIMEBH
+#include <sys/timeb.h>
+#endif /* SYSTIMEBH */
+#endif /* NOSYSTIMEBH */
+
+#ifndef TIMEH
+#ifndef SYSTIMEH
+#ifndef SYSTIMEBH
+#ifdef Plan9
+#include <sys/time.h>
+#else
+#ifdef AIX41
+#include <time.h>
+#else
+#ifdef SUNOS4
+#include <sys/time.h>
+#else
+#ifdef SYSTIMEH
+#include <sys/time.h>
+#else
+#ifdef POSIX
+#include <posix/time.h>
+#else
+#ifdef CLIX
+#include <sys/time.h>
+#else
+#ifdef OS2
+#include <time.h>
+#else
+#include <time.h>
+/* #include <utime.h> */
+#endif /* OS2 */
+#endif /* CLIX */
+#endif /* POSIX */
+#endif /* SYSTIMEH */
+#endif /* SUNOS4 */
+#endif /* AIX41 */
+#endif /* Plan9 */
+#endif
+#endif
+#endif
+
+#ifdef OS2
+#include <sys/utime.h>
+#ifdef NT
+#define utimbuf _utimbuf
+#endif /* NT */
+#define utime   _utime
+#else
+#ifdef SYSUTIMEH                        /* <sys/utime.h> if requested,  */
+#include <sys/utime.h>                  /* for extra fields required by */
+#else                                   /* 88Open spec. */
+#ifdef UTIMEH                           /* or <utime.h> if requested */
+#include <utime.h>                      /* (SVR4, POSIX) */
+#define SYSUTIMEH                       /* Use this for both cases. */
+#endif /* UTIMEH */
+#endif /* SYSUTIMEH */
+#endif /* OS2 */
+
+#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(&ltime);
+
+    gmt = gmtime(&ltime);               /* 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;
+        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, x, dns = 0;
+#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 < 0
+#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 <netdb.h> */
+            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 */
+#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);
+            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 <arpa/inet.h> 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);
+
+    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
+http_tol(s,n) CHAR *s; int n; {
+    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
+    hexdump("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
+http_inc(timo) int timo; {
+    int x=-1; unsigned char c;             /* The locals. */
+
+    if (httpfd == -1) {
+        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 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);
+                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) {
+                        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) {
+                        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;
+            }
+        }
+#else /* !IBMSELECT */
+        SELECT is required for this code
+#endif /* IBMSELECT */
+#endif /* BSDSELECT */
+    }
+
+    if (timo && x < 0) {        /* select() timed out */
+        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 TCPIPLIB
+        x = socket_read(httpfd,&c,1);
+#else
+        x = read(httpfd,&c,1);
+#endif
+
+        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;
+            }
+            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)) != 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 mod_t;
+    time_t srv_t;
+    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 mod_t;
+    time_t srv_t;
+    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;
+                }
+                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)) != 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 mod_t;
+    time_t srv_t;
+    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
+    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) {
+        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;
+                    }
+                    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)) != 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 mod_t;
+    time_t srv_t;
+    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
+    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) {
+        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;
+                }
+                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)) != 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 mod_t;
+    time_t srv_t;
+    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);
+    ckstrncat(request,"\r\n",len);
+
+    /* 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;
+                    }
+                    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)) != 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 mod_t;
+    time_t srv_t;
+    time_t local_t;
+    char passwd[64];
+    char b64in[128];
+    char b64out[256];
+    char * headers[HTTPHEADCNT];
+    int    connected = 0;
+    int    chunked = 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
+locate_srv_dns(host, service, protocol, addr_pp, naddrs)
+    char *host;
+    char *service;
+    char *protocol;
+    struct sockaddr **addr_pp;
+    int *naddrs;
+{
+    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
+locate_txt_rr(prefix, name, retstr)
+    char *prefix, *name;
+    char **retstr;
+{
+    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 <sys/un.h>
+#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 */
+int
+fwdx_create_listen_socket(screen) int screen; {
+#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
+fwdx_open_client_channel(channel) int channel; {
+    char * env;
+    struct sockaddr_in saddr;
+#ifdef FWDX_UNIX_SOCK
+    struct sockaddr_un saddr_un = { AF_LOCAL };
+#endif /* FWDX_UNIX_SOCK */
+    int colon, dot, 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<MAXFWDX ; i++ ) {
+        if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
+            /* Already open */
+            debug(F110,"fwdx_create_client_channel()","already open",0);
+            return(0);
+        }
+    }
+
+    env = getenv("DISPLAY");
+    if ( !env )
+        env = 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) {
+        debug(F100,"fwdx_create_client_channel() FamilyLocal","",0);
+        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) {
+        if (host) free(host);
+        sock = socket(PF_LOCAL, SOCK_STREAM, 0);
+        if (sock < 0)
+            return(-1);
+
+        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(-1);
+    } else
+#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_create_client_channel()","display",display);
+
+        port = 6000 + display;
+        saddr.sin_port = htons(port);
+
+        debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
+        saddr.sin_addr.s_addr = inet_addr(buf);
+        if ( saddr.sin_addr.s_addr == (unsigned long) -1
+#ifdef INADDR_NONE
+             || saddr.sin_addr.s_addr == INADDR_NONE
+#endif /* INADDR_NONE */
+             )
+        {
+            struct hostent *host;
+            host = gethostbyname(buf);
+            if ( host == NULL )
+                return(-1);
+            host = ck_copyhostent(host);
+#ifdef HADDRLIST
+#ifdef h_addr
+            /* This is for trying multiple IP addresses - see <netdb.h> */
+            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 colon, dot, display, port, sock, i, screen;
+    char buf[256], *host=NULL, *rest=NULL;
+#ifdef TCP_NODELAY
+    int on=1;
+#endif /* TCP_NODELAY */
+    int family;
+
+    env = getenv("DISPLAY");
+    if ( !env )
+        env = 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 == (unsigned long) -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 <netdb.h> */
+        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,i;
+#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;
+    char sb[8];
+    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 */
+    unsigned short nchannel;
+    unsigned char * p;
+
+    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<MAXFWDX;channel++ ) {
+        if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
+            break;
+    }
+
+    if ( channel == MAXFWDX ) {
+#ifdef TCPIPLIB
+        socket_close(sock2);
+#else /* TCPIPLIB */
+        close(sock2);
+#endif /* TCPIPLIB */
+        return(-1);
+    }
+
+    if ( fwdx_send_open(channel) < 0 ) {
+#ifdef TCPIPLIB
+        socket_close(sock2);
+#else /* TCPIPLIB */
+        close(sock2);
+#endif /* TCPIPLIB */
+    }
+
+#ifdef TCP_NODELAY
+    setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
+#endif /* TCP_NODELAY */
+
+    TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
+    TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
+    goto try_again;
+
+    return(0);  /* never reached */
+}
+
+int
+fwdx_close_channel(channel) int channel; {
+    int i,fd;
+
+    for ( i=0; i<MAXFWDX ; i++ ) {
+        if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
+            break;
+    }
+    if ( i == MAXFWDX )
+        return(-1);
+
+    fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
+    TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
+    TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
+    TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
+
+#ifdef TCPIPLIB
+    socket_close(fd);
+#else /* TCPIPLIB */
+    close(fd);
+#endif /* TCPIPLIB */
+    return(0);
+}
+
+int
+fwdx_close_all() {
+    int x,fd;
+
+    debug(F111,"fwdx_close_all()",
+          "TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket",
+          TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
+
+    if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
+#ifdef TCPIPLIB
+        socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
+#else /* TCPIPLIB */
+        close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
+#endif /* TCPIPLIB */
+        TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
+    }
+
+    for (x = 0; x < MAXFWDX; x++) {
+     if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
+      fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
+      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;
+#ifdef TCPIPLIB
+      socket_close(fd);
+#else /* TCPIPLIB */
+      close(fd);
+#endif /* TCPIPLIB */
+     }
+    }
+    return(0);
+}
+
+/* The following definitions are for Unix */
+#ifndef socket_write
+#define socket_write(f,s,n)    write(f,s,n)
+#endif /* socket_write */
+#ifndef socket_read
+#define socket_read(f,s,n)     read(f,s,n)
+#endif /* socket_read */
+
+int
+fwdx_write_data_to_channel(channel, data, len)
+    int channel; char * data; int len;
+{
+    int sock, count, try=0, length = len, i;
+
+    if ( len <= 0 )
+        return(0);
+
+    for ( i=0; i<MAXFWDX ; i++ ) {
+        if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
+            break;
+    }
+    if ( i == MAXFWDX ) {
+        debug(F110,"fwdx_write_data_to_channel",
+               "attempting to write to closed channel",0);
+        return(-1);
+    }
+
+    sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
+    debug(F111,"fwdx_write_data_to_channel","socket",sock);
+    hexdump("fwdx_write_data_to_channel",data,len);
+
+  fwdx_write_data_to_channel_retry:
+
+    if ((count = socket_write(sock,data,len)) < 0) {
+        int s_errno = socket_errno; /* maybe a function */
+        debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
+#ifdef BETATEST
+        printf("fwdx_write_data_to_channel error\r\n");
+#endif /* BETATEST */
+#ifdef OS2
+        if (os2socketerror(s_errno) < 0)
+            return(-2);
+#endif /* OS2 */
+        return(-1);                 /* Call it an i/o error */
+    }
+    if (count < len) {
+        debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
+        if (count > 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 */
diff --git a/ckermit-8.0.211/ckcnet.h b/ckermit-8.0.211/ckcnet.h
new file mode 100644
index 0000000..c8d5576
--- /dev/null
+++ b/ckermit-8.0.211/ckcnet.h
@@ -0,0 +1,1441 @@
+/* ckcnet.h -- Symbol and macro definitions for C-Kermit network support */
+
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 */
+/* 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 netbreak, (void) );
+_PROTOTYP( int netinc, (int) );
+_PROTOTYP( int netxin, (int, CHAR *) );
+_PROTOTYP( int nettol, (CHAR *, int) );
+_PROTOTYP( int nettoc, (CHAR) );
+/*
+  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 <fcntl.h>
+#include <errno.h>
+#include <sys/ioccom.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sundev/syncstat.h>
+#include <netx25/x25_pk.h>
+#include <netx25/x25_ctl.h>
+#include <netx25/x25_ioctl.h>
+#else
+#include <sys/ioctl.h>                  /* X.25 includes, Sun only */
+#include <sys/systm.h>
+#ifndef SOLARIS
+#include <sys/mbuf.h>
+#endif /* SOLARIS */
+#include <sys/socket.h>
+#include <sys/protosw.h>
+#ifdef SOLARIS
+#include <sys/sockio.h>
+#else
+#include <sys/domain.h>
+#endif /* SOLARIS */
+#include <sys/socketvar.h>
+#include <net/if.h>
+#include <sundev/syncstat.h>
+#include <netx25/x25_pk.h>
+#include <netx25/x25_ctl.h>
+#include <netx25/x25_ioctl.h>
+#endif /* SOLARIS25 */
+#endif /* SUNX25 */
+
+#ifdef ANYX25
+
+#ifdef IBMX25                           /* X.25 includes, AIX only */
+#include <fcntl.h>
+#include <sys/twtypes.h>
+#include <sys/twlib.h>
+
+#include <sys/stream.h>
+#include <stropts.h>
+
+#define NPI_20                          /* required to include the whole NPI */
+#include <sys/npi_20.h>
+#include <sys/npiapi.h>
+#include <sys/pktintf.h>
+
+#include <odmi.h>                       /* required for access to the ODM   */
+#include <sys/cfgodm.h>                 /* 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 <x25/ccittproto.h>
+#include <x25/x25.h>
+#include <x25/x25addrstr.h>
+#include <x25/x25codes.h>
+#include <x25/x25hd_ioctl.h>
+#include <x25/x25ioctls.h>
+#include <x25/x25str.h>
+#include <sys/ioctl.h>
+#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 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 <mboucher@iro.umontreal.ca> 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 <interlan/socket.h>
+#include <interlan/il_types.h>
+#include <interlan/telnet.h>
+#include <interlan/il_errno.h>
+#include <interlan/in.h>
+#include <interlan/telnet.h>            /* Why twice ? ? ? */
+#else /* Not Interlan */
+#ifdef BEBOX
+#include <socket.h>
+#else /* Not BEBOX */                   /* Normal BSD TCP/IP library */
+#ifdef COMMENT
+#ifndef HPUX
+#include <arpa/telnet.h>
+#endif /* HPUX */
+#endif /* COMMENT */
+#ifdef SCO234
+#include <sys/errno.tcp.h>
+#include <sys/types.tcp.h>
+#endif /* SCO234 */
+#include <sys/socket.h>
+#ifdef WOLLONGONG
+#include <sys/in.h>
+#else
+#include <netinet/in.h>
+#ifndef SV68R3V6                /* (maybe this should be SVR3 in general) */
+#include <netinet/tcp.h>        /* Added June 2001 */
+#endif /* SV68R3V6 */
+#endif /* WOLLONGONG */
+#endif /* BEBOX */
+#endif /* INTERLAN */
+
+#ifndef EXCELAN
+#include <netdb.h>
+#ifndef INTERLAN
+#ifdef WOLLONGONG
+#define minor                           /* Do not include <sys/macros.h> */
+#include <sys/inet.h>
+#else
+#ifndef OXOS
+#ifndef HPUX
+#ifndef BEBOX
+#include <arpa/inet.h>
+#endif /* BEBOX */
+#endif /* HPUX */
+#else /* OXOS */
+/* In too many releases of X/OS, <arpa/inet.h> 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 <ex_errno.h>
+#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 <errno.h> and <net/errno.h> */
+#define ORG_NEMPTY ENOTEMPTY
+#undef ENOTEMPTY
+#include <net/errno.h>
+#undef ENAMETOOLONG
+#define ENAMETOOLONG ORG_NLONG
+#undef ENOTEMPTY
+#define ENOTEMPTY ORG_NEMPTY
+#include <netinet/tcp.h>                /* 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 <arpa/inet.h> 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"
+
+#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 <strings.h> 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 <errno.h>
+#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 <if.h>                         /* Needed to put up u_int typedef */
+#else
+#ifdef NEEDUINT
+typedef unsigned int u_int;
+#endif /* NEEDUINT */
+#endif /* IF_DOT_H */
+
+#include <in.h>
+#include <netdb.h>
+#include <socket.h>
+#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 <strings.h>, 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 <strings.h>
+#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 <types.h>
+#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 <types.h>
+#include <in.h>
+#include <netdb.h>
+#include <socket.h>
+#include <inet.h>
+#include <ioctl.h>
+#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 <nerrno.h>
+#endif
+#endif /* OS2 */
+
+#ifdef STRATUS  /* Stratus VOS using OS TCP/IP products S235, S236, S237 */
+#include <tcp_socket.h>
+/* 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 <inet/in.h>
+#include <inet/netdb.h>
+#include <inet/socket.h>
+#else
+#include <INET/in.h>
+#include <INET/netdb.h>
+#include <INET/socket.h>
+#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 */
+
+#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
+#define IKS_OPTION
+#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() */
+
+#ifndef SOCKOPT_T
+#define SOCKOPT_T int
+#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 /* SOCKOPT_T */
+
+/* Ditto for getsockname() */
+
+#ifndef GSOCKNAME_T
+#define GSOCKNAME_T int
+#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 /* GSOCKNAME_T */
+
+#endif /* TCPSOCKET */
+
+#ifdef MACOSX10
+#ifdef bcopy
+#undef bcopy
+#endif
+#ifdef bzero
+#undef bzero
+#endif
+#endif /* MACOSX10 */
+
+#endif /* CKCNET_H */
diff --git a/ckermit-8.0.211/ckcplm.txt b/ckermit-8.0.211/ckcplm.txt
new file mode 100644
index 0000000..9c2f44f
--- /dev/null
+++ b/ckermit-8.0.211/ckcplm.txt
@@ -0,0 +1,3076 @@
+
+                         C-Kermit Program Logic Manual
+
+     Frank da Cruz
+     [1]The Kermit Project
+     [2]Columbia University
+
+   As of: C-Kermit 8.0.211, 10 April 2004
+   This page last updated: Sat Apr 10 16:45:30 2004 (New York USA Time)
+
+     IF YOU ARE READING A PLAIN-TEXT version of this document, note that
+     this file is a plain-text dump of a Web page. You can visit the
+     original (and possibly more up-to-date) Web page here:
+
+  [3]http://www.columbia.edu/kermit/ckcplm.html
+
+   [ [4]C-Kermit Home ] [ [5]Kermit Home ]
+    ________________________________________________________________________
+
+  CONTENTS
+
+  1. [6]INTRODUCTION
+  2. [7]FILES
+  3. [8]SOURCE CODE PORTABILITY AND STYLE
+  4. [9]MODULES
+     4.A. [10]Group A: Library Routines
+     4.B. [11]Group B: Kermit File Transfer
+     4.C. [12]Group C: Character-Set Conversion
+     4.D. [13]Group D: User Interface
+     4.E. [14]Group E: Platform-Dependent I/O
+     4.F. [15]Group F: Network Support
+     4.G. [16]Group G: Formatted Screen Support
+     4.H. [17]Group H: Pseudoterminal Support
+     4.I. [18]Group I: Security
+  I. [19]APPENDIX I: FILE PERMISSIONS
+    ________________________________________________________________________
+
+  1. INTRODUCTION
+
+   The Kermit Protocol is specified in the book Kermit, A File Transfer
+   Protocol by Frank da Cruz, Digital Press / Butterworth Heinemann,
+   Newton, MA, USA (1987), 379 pages, ISBN 0-932376-88-6. It is assumed
+   the reader is familiar with the Kermit protocol specification.
+
+   This file describes the relationship among the modules and functions
+   of C-Kermit 5A and later, and other programming considerations.
+   C-Kermit is designed to be portable to any kind of computer that has a
+   C compiler. The source code is broken into many files that are grouped
+   according to their function, as shown in the [20]Contents.
+
+   C-Kermit has seen constant development since 1985. Throughout its
+   history, there has been a neverending tug-of-war among:
+
+    a. Functionality: adding new features, fixing bugs, improving
+       performance.
+    b. Adding support for new platforms.
+    c. "Buzzword 1.0 compliance".
+
+   The latter category is the most frustrating, since it generally
+   involves massive changes just to keep the software doing what it did
+   before in some new setting: e.g. the K&R-to-ANSIC conversion (which
+   had to be done, of course, without breaking K&R); Y2K (not a big deal
+   in our case); the many and varied UNIX and other API "standards";
+   IPv6.
+
+   [ [21]Contents ] [ [22]C-Kermit ] [ [23]Kermit Home ]
+    ________________________________________________________________________
+
+  2. FILES
+
+   C-Kermit source files begin with the two letters "ck", for example
+   ckutio.c. Filenames are kept short (6.3) for maximum portability and
+   (obviously I hope) do not contain spaces or more than one period. The
+   third character in the name denotes something about the function group
+   and the expected level of portability:
+
+     a     General descriptive material and documentation (text)
+     b     BOO file encoders and decoders (obsolete)
+     c     All platforms with C compilers (*)
+     d     Data General AOS/VS
+     e     Reserved for "ckermit" files, like ckermit.ini, ckermit2.txt
+     f     (reserved)
+     g     (reserved)
+     h     (reserved)
+     i     Commodore Amiga (Intuition)
+     j     (unused)
+     k     (unused)
+     l     Stratus VOS
+     m     Macintosh with Mac OS 1-9
+     n     Microsoft Windows NT/2000/XP
+     o     OS/2 and/or Microsoft Windows 9x/ME/NT/2000/XP
+     p     Plan 9 from Bell Labs
+     q     (reserved)
+     r     DEC PDP-11 with RSTS/E (never used, open for reassigment)
+     s     Atari ST GEMDOS (last supported in version 5A(189))
+     t     DEC PDP-11 with RT-11 (never used, open for reassigment)
+     u     Unix-based operating systems (*)
+     v     VMS and OpenVMS
+     w     Wart (Lex-like preprocessor, platform independent)
+     x     (reserved)
+     y     (reserved)
+     z     (reserved)
+     0-3   (reserved)
+     4     IBM AS/400
+     5-8   (reserved)
+     9     Microware OS-9
+     _     Encryption modules
+
+   (*) In fact there is little distinction between the ckc*.* and cku*.*
+   categories. It would make more sense for all cku*.* modules to be
+   ckc*.* ones, except ckufio.c, ckutio.c, ckucon.c, ckucns.c, and
+   ckupty.c, which truly are specific to Unix. The rest (ckuus*.c,
+   ckucmd.c, etc) are quite portable.
+
+   One hint before proceeding: functions are scattered all over the
+   ckc*.c and cku*.c modules, where function size has begun to take
+   precedence over the desirability of grouping related functions
+   together, the aim being to keep any particular module from growing
+   disproportionately large. The easiest way (in UNIX) to find out in
+   what source file a given function is defined is like this (where the
+   desired function is foo()...):
+
+  grep ^foo\( ck*.c
+
+   This works because the coding convention has been to make function
+   names always start on the left margin with their contents indented,
+   for example:
+
+static char *
+foo(x,y) int x, y; {
+    ...
+}
+
+   Also note the style for bracket placement. This allows
+   bracket-matching text editors (such as EMACS) to help you make sure
+   you know which opening bracket a closing bracket matches, particularly
+   when the opening bracket is above the visible screen, and it also
+   makes it easy to find the end of a function (search for '}' on the
+   left margin).
+
+   Of course EMACS tags work nicely with this format too:
+
+  $ cd kermit-source-directory
+  $ etags ck[cu]*.c
+  $ emacs
+  Esc-X Visit-Tags-Table<CR><CR>
+
+   (but remember that the source file for ckcpro.c is [24]ckcpro.w!)
+
+   Also:
+
+     * Tabs should be set every 8 spaces, as on a VT100.
+     * All lines must no more than 79 characters wide after tab
+       expansion.
+     * Note the distinction between physical tabs (ASCII 9) and the
+       indentation conventions, which are: 4 for block contents, 2 for
+       most other stuff (obviously this is not a portability issue, just
+       style).
+
+   [ [25]Contents ] [ [26]C-Kermit ] [ [27]Kermit Home ]
+    ________________________________________________________________________
+
+  3. SOURCE CODE PORTABILITY AND STYLE
+
+   C-Kermit was designed in 1985 as a platform-independent replacement
+   for the earlier Unix Kermit. c-Kermit's design was expected to promote
+   portability, and judging from the number of platforms to which it has
+   been adapted since then, the model is effective, if not ideal
+   (obviously if we had it all to do over, we'd change a few things). To
+   answer the oft-repeated question: "Why are there so many #ifdefs?",
+   it's because:
+
+     * Many of them are related to feature selection and program size,
+       and so need to be there anyway.
+     * Those that treat compiler, library, platform, header-file, and
+       similar differences have built up over time as hundreds of people
+       all over the world adapted C-Kermit to their particular
+       environments and sent back their changes. There might be more
+       politically-correct ways to achieve portability, but this one is
+       natural and proven. The basic idea is to introduce changes that
+       can be selected by defining a symbol, which, if not defined,
+       leaves the program exactly as it was before the changes.
+     * Although it might be possible to "clean up" the "#ifdef mess",
+       nobody has access to all the hundreds of platforms served by the
+       #ifdefs to check the results.
+
+   And to answer the second-most-oft-repeated question: "Why don't you
+   just use GNU autoconfig / automake / autowhatever instead of
+   hard-coding all those #ifdefs?" Answers:
+
+     * The GNU tools are not available on all the platforms where
+       C-Kermit must be built and I wouldn't necessarily trust them if
+       they were.
+     * Each platform is a moving target, so the tools themselves would
+       need to updated before Kermit could be updated.
+     * It would only add another layer of complexity to an already
+       complex process.
+     * Conversion at this point would not be practical unless there was a
+       way to test the results on all the hundreds of platforms where
+       C-Kermit is supposed to build.
+
+   When writing code for the system-indendent C-Kermit modules, please
+   stick to the following coding conventions to ensure portability to the
+   widest possible variety of C preprocessors, compilers, and linkers, as
+   well as certain network and/or email transports. The same holds true
+   for many of the "system dependent" modules too; particularly the Unix
+   ones, since they must be buildable by a wide variety of compilers and
+   linkers, new and old.
+
+   This list does not purport to be comprehensive, and although some
+   items on it might seem far-fetched, they would not be listed unless I
+   had encountered them somewhere, some time. I wish I had kept better
+   records so I could cite specific platforms and compilers.
+
+     * Try to keep variable and function names unique within 6
+       characters, especially if they are used across modules, since 6 is
+       the maximum for some old linkers (actually, this goes back to
+       TOPS-10 and -20 and other old DEC OS's where C-Kermit never ran
+       anyway; a more realistic maximum is probably somewhere between 8
+       and 16). We know for certain that VAX C has a 31-character max
+       because it complains -- others might not complain, but just
+       silently truncate, thus folding two or more routines/variables
+       into one.
+     * Keep preprocessor symbols unique within 8 characters; that's the
+       max for some preprocessors (sorry, I can't give a specific
+       example, but in 1988 or thereabouts, I had to change character-set
+       symbols like TC_LATIN1 and TC_LATIN2 to TC_1LATIN and TC_2LATIN
+       because the digits were being truncated and ignored on a platform
+       where I actually had to build C-Kermit 5A; unfortunately I didn't
+       note which platform -- maybe some early Ultrix version?)
+     * Don't create preprocessor symbols, or variable or function names,
+       that start with underscore (_). These are usually reserved for
+       internal use by the compiler and header files.
+     * Don't put #include directives inside functions or { blocks }.
+     * Don't use the #if or #elif preprocessor constructions, only use
+       #ifdef, #ifndef, #define, #undef, and #endif.
+     * Put tokens after #endif in comment brackets, e.g.
+       #endif /* FOO */.
+     * Don't indent preprocessor statements - # must always be first char
+       on line.
+     * Don't put whitespace after # in preprocessor statements.
+     * Don't use #pragma, even within #ifdefs -- it makes some
+       preprocessors give up.
+     * Same goes for #module, #if, etc - #ifdefs do NOT protect them.
+     * Don't use logical operators in preprocessor constructions.
+     * Avoid #ifdefs inside argument list to function calls (I can't
+       remember why this one is here, but probably needn't be; we do this
+       all the time).
+     * Always cast strlen() in expressions to int:
+       if ((int)strlen(foo) < x)...
+     * Any variable whose value might exceed 16383 should be declared as
+       long, or if that is not possible, then as unsigned.
+     * Avoid typedefs; they might be portable but they are very confusing
+       and there's no way to test for their presence or absence at
+       compile time. Use preprocessor symbols instead if possible; at
+       least you can test their definitions.
+     * Unsigned long is not portable; use a preprocessor symbol (Kermit
+       uses ULONG for this).
+     * Long long is not portable. If you really need it, be creative.
+     * Similarly 1234LL is not portable, nor almost any other constant
+       modifier other than L.
+     * Unsigned char is not portable, use CHAR (a preprocessor symbol
+       defined in the Kermit header files) and always take precautions
+       against character signage (more about this [28]below).
+     * Don't use initializers with automatic arrays or structs: it's not
+       portable.
+     * Don't use big automatic arrays or structs in functions that might
+       be called recursively; some platforms have fixed-size stacks (e.g.
+       Windows 9x: 256K) and recursive functions crash with stack
+       overflow. Even when there is not a compiler limitation, this
+       causes memory to be consumed without bound, and can end up filling
+       swap space.
+     * Don't assume that struct assignment performs a copy, or that it
+       even exists.
+     * Don't use sizeof to get the size of an array; someone might come
+       along later and and change it from static to malloc'd. Always use
+       a symbol to refer to the array's size.
+     * Don't put prototypes for static functions into header files that
+       are used by modules that don't contain that function; the link
+       step can fail with unresolved references (e.g. on AOS/VS).
+     * Avoid the construction *++p (the order of evaluation varies; it
+       shouldn't but at least one compiler had a bug that made me include
+       this item).
+     * Don't use triple assignments, like a = b = c = 0; (or quadruple,
+       etc). Some compilers generate bad code for these, or crash, etc
+       (some version of DEC C as I recall).
+     * Some compilers don't allow structure members to have the same
+       names as other identifiers. Try to give structure members unique
+       names.
+     * Don't assume anything about order of evaluation in boolean
+       expressions, or that they will stop early if a required condition
+       is not true, e.g.:
+  if (i > 0 && p[i-1] == blah)
+       can still dump core if i == 0 (hopefully this is not true of any
+       modern compiler, but I would not have said this if it did not
+       actually happen somewhere).
+     * Don't have a switch() statement with no cases (e.g. because of
+       #ifdefs); this is a fatal error in some compilers.
+     * Don't put lots of code in a switch case; move it out to a separate
+       function; some compilers run out of memory when presented with a
+       huge switch() statement -- it's not the number of cases that
+       matters; it's the overall amount of code.
+     * Some compilers might also limit the number of switch() cases, e.g.
+       to 254.
+     * Don't put anything between "switch() {" and "case:" -- switch
+       blocks are not like other blocks.
+     * Don't jump into or out of switches.
+     * Don't make character-string constants longer than about 250 bytes.
+       Longer strings should be broken up into arrays of strings.
+     * Don't write into character-string constants (obviously). Even when
+       you know you are not writing past the end; the compiler or linker
+       might have put them into read-only and/or shared memory, and/or
+       coalesced multiple equal constants so if you change one you change
+       them all.
+     * Don't depend on '\r' being carriage return.
+     * Don't depend on '\n' being linefeed or for that matter any SINGLE
+       character.
+     * Don't depend on '\r' and '\n' being different (e.g. as separate
+       switch() cases).
+     * In other words, don't use \n or \r to stand for specific
+       characters; use \012 and \015 instead.
+     * Don't code for "buzzword 1.0 compliance", unless "buzzword" is K&R
+       and "1.0" is the first edition.
+     * Don't use or depend on anything_t (size_t, pid_t, etc), except
+       time_t, without #ifdef protection (time_t is the only one I've
+       found that is accepted everywhere). This is a tough one because
+       the same function might require (say) a size_t arg on one
+       platform, whereas size_t is unheard of on another; or worse, it
+       might require a totally different data type, like int or long or
+       some other typedef'd thing. It has often proved necessary to
+       define a symbol to stand for the type of a particular argument to
+       a particular library or system function to get around this
+       problem.
+     * Don't use or depend on internationalization ("i18n") features,
+       wchar_t, locales, etc, in portable code; they are not portable.
+       Anyway, locales are not the right model for Kermit's
+       multi-character-set support. Kermit does all character-set
+       conversion itself and does not use any external libraries or
+       functions.
+     * In particular, don't use any library functions that deal with wide
+       characters or Unicode in any form. These are not only nonportable,
+       but a constantly shifting target (e.g. the ones in glibc).
+     * Don't make any assumption about signal handler type. It can be
+       void, int, long, or anything else. Always declare signal handlers
+       as SIGTYP (see definition in ckcdeb.h and augment it if necessary)
+       and always use SIGRETURN at exit points from signal handlers.
+     * Signals should always be re-armed to be used again (this barely
+       scratches the surface -- the differences between BSD/V7 and System
+       V and POSIX signal handling are numerous, and some platforms do
+       not even support signals, alarms, or longjmps correctly or at all
+       -- avoid all of this if you can).
+     * On the other hand, don't assume that signals are disarmed after
+       being raised. In some platforms you have to re-arm them, in others
+       they stay armed.
+     * Don't call malloc() and friends from a signal handler; don't do
+       anything but setting integer global variables in a signal handler.
+     * malloc() does not initialize allocated memory -- it never said it
+       did. Don't expect it to be all 0's.
+     * Did You Know: malloc() can succeed and the program can still dump
+       core later when it attempts to use the malloc'd memory? (This
+       happens when allocation is deferred until use and swap space is
+       full.)
+     * memset(), memmove(), and memcpy() are not portable, don't use them
+       without protecting them in ifdefs (we have USE_MEMCPY for this).
+       bzero()/bcopy() too, except we're guaranteed to have
+       bzero()/bcopy() when using the sockets library (not really). See
+       examples in the source.
+     * Don't assume that strncpy() stops on the first null byte -- most
+       versions always copy the number of bytes given in arg 3, padding
+       out with 0's and overwriting whatever was there before. Use
+       C-Kermit ckstrncpy() if you want predictable non-padding behavior,
+       guaranteed NUL-termination, and a useful return code.
+     * DID YOU KNOW.. that some versions of inet_blah() routines return
+       IP addresses in network byte order, while others return them local
+       machine byte order? So passing them to ntohs() or whatever is not
+       always the right thing to do.
+     * Don't use ANSI-format function declarations without #ifdef
+       CK_ANSIC, and always provide an #else for the non-ANSI case.
+     * Use the Kermit _PROTOTYP() macro for declaring function
+       prototypes; it works in both the ANSI and non-ANSI cases.
+     * Don't depend on any other ANSI preprocessor features like
+       "pasting" -- they are often missing or nonoperational.
+     * Don't assume any C++ syntax or semantics.
+     * Don't use // as a comment introducer. C is not C++.
+     * Don't declare a string as "char foo[]" in one module and "extern
+       char * foo" in another, or vice-versa: this causes core dumps.
+     * With compiler makers falling all over themselves trying to outdo
+       each other in ANSI strictness, it has become increasingly
+       necessary to cast EVERYTHING. This is increasingly true for char
+       vs unsigned char. We need to use unsigned chars if we want to deal
+       with 8-bit character sets, but most character- and string-oriented
+       APIs want (signed) char arguments, so explicit casts are
+       necessary. It would be nice if every compiler had a
+       -funsigned-char option (as gcc does), but they don't.
+     * a[x], where x is an unsigned char, can produce a wild memory
+       reference if x, when promoted to an int, becomes negative. Cast it
+       to (unsigned), even though it ALREADY IS unsigned.
+     * Be careful how you declare functions that have char or long
+       arguments; for ANSI compilers you MUST use ANSI declarations to
+       avoid promotion problems, but you can't use ANSI declarations with
+       non-ANSI compilers. Thus declarations of such functions must be
+       hideously entwined in #ifdefs. Example: latter:
+  int                          /*  Put character in server command buffer  */
+  #ifdef CK_ANSIC
+  putsrv(char c)
+  #else
+  putsrv(c) char c;
+  #endif /* CK_ANSIC */
+  /* putsrv */ {
+      *srvptr++ = c;
+      *srvptr = '\0';           /* Make sure buffer is null-terminated */
+      return(0);
+  }
+     * Be careful how you return characters from functions that return
+       int values -- "getc-like functions" -- in the ANSI world. Unless
+       you explicitly cast the return value to (unsigned), it is likely
+       to be "promoted" to an int and have its sign extended.
+     * At least one compiler (the one on DEC OSF/1 1.3) treats "/*" and
+       "*/" within string constants as comment begin and end. No amount
+       of #ifdefs will get around this one. You simply can't put these
+       sequences in a string constant, e.g. "/usr/local/doc/*.*".
+     * Avoid putting multiple macro references on a single line, e.g.:
+  putchar(BS); putchar(SP); putchar(BS)
+
+   This overflows the CPP output buffer of more than a few C
+   preprocessors (this happened, for example, with SunOS 4.1 cc, which
+   evidently has a 1K macro expansion buffer).
+
+   C-Kermit needs constant adjustment to new OS and compiler releases.
+   Every new OS release shuffles header files or their contents, or
+   prototypes, or data types, or levels of ANSI strictness, etc. Every
+   time you make an adjustment to remove a new compilation error, BE VERY
+   CAREFUL to #ifdef it on a symbol unique to the new configuration so
+   that the previous configuration (and all other configurations on all
+   other platforms) remain as before.
+
+   Assume nothing. Don't assume header files are where they are supposed
+   to be, that they contain what you think they contain, that they define
+   specific symbols to have certain values -- or define them at all!
+   Don't assume system header files protect themselves against multiple
+   inclusion. Don't assume that particular system or library calls are
+   available, or that the arguments are what you think they are -- order,
+   data type, passed by reference vs value, etc. Be conservative when
+   attempting to write portable code. Avoid all advanced features.
+
+   If you see something that does not make sense, don't assume it's a
+   mistake -- it might be there for a reason, and changing it or removing
+   is likely to cause compilation, linking, or runtime failures sometime,
+   somewhere. Some huge percentage of the code, especially in the
+   platform-dependent modules, is workarounds for compiler, linker, or
+   API bugs.
+
+   But finally... feel free to violate any or all of these rules in
+   platform-specific modules for environments in which the rules are
+   certain not to apply. For example, in VMS-specific code, it is OK to
+   use #if, because VAX C, DEC C, and VMS GCC all support it.
+
+   [ [29]Contents ] [ [30]C-Kermit ] [ [31]Kermit Home ]
+    ________________________________________________________________________
+
+  3.1. Memory Leaks
+
+   The C language and standard C library are notoriously inadequate and
+   unsafe. Strings are arrays of characters, usually referenced through
+   pointers. There is no native string datatype. Buffers are fixed size,
+   and C provides no runtime bounds checking, thus allowing overwriting
+   of other data or even program code. With the popularization of the
+   Internet, the "buffer exploit" has become a preferred method for
+   hackers to hijack privileged programs; long data strings are fed to a
+   program in hopes that it uses unsafe C library calls such as strcpy()
+   or sprintf() to copy strings into automatic arrays, thus overwriting
+   the call stack, and therefore the routine's return address. When such
+   a hole is discovered, a "string" can be constructed that contains
+   machine code to hijack the program's privileges and penetrate the
+   system.
+
+   This problem is partially addressed by the strn...() routines, which
+   should always be used in preference to their str...() equivalents
+   (except when the copy operation has already been prechecked, or there
+   is a good reason for not using them, e.g. the sometimes undesirable
+   side effect of strncpy() zeroing the remainder of the buffer). The
+   most gaping whole, however, is sprintf(), which performs no length
+   checking on its destination buffer, and is not easy to replace.
+   Although snprintf() routines are starting to appear, they are not yet
+   widespread, and certainly not universal, nor are they especially
+   portable, or even full-featured.
+
+   For these reasons, we have started to build up our own little library
+   of C Library replacements, ckclib.[ch]. These are safe and highly
+   portable primitives for memory management and string manipulation,
+   such as:
+
+   ckstrncpy()
+          Like strncpy but returns a useful value, doesn't zero buffer.
+
+   ckitoa()
+          Opposite of atoi()
+
+   ckltoa()
+          Opposite of atol()
+
+   ckctoa()
+          Returns character as string
+
+   ckmakmsg()
+          Used with ck?to?() as a safe sprintf() replacement for up to 4
+          items
+
+   ckmakxmsg()
+          Like ckmakmsg() but accepts up to 12 items
+
+   More about library functions in [32]Section 4.A.
+
+   [ [33]Contents ] [ [34]C-Kermit ] [ [35]Kermit Home ]
+    ________________________________________________________________________
+
+  3.2. The "char" vs "unsigned char" Dilemma
+
+   This is one of the most aggravating and vexing characteristics of the
+   C language. By design, chars (and char *'s) are SIGNED. But in the
+   modern era, however, we need to process characters that can have (or
+   include) 8-bit values, as in the ISO Latin-1, IBM CP 850, or UTF-8
+   character sets, so this data must be treated as unsigned. But some C
+   compilers (such as those based on the Bell UNIX V7 compiler) do not
+   support "unsigned char" as a data type. Therefore we have the macro or
+   typedef CHAR, which we use when we need chars to be unsigned, but
+   which, unfortunately, resolves itself to "char" on those compilers
+   that don't support "unsigned char". AND SO... We have to do a lot of
+   fiddling at runtime to avoid sign extension and so forth.
+
+   Some modern compilers (e.g. IBM, DEC, Microsoft) have options that say
+   "make all chars be unsigned" (e.g. GCC "-funsigned-char") and we use
+   them when they are available. Other compilers don't have this option,
+   and at the same time, are becoming increasingly strict about type
+   mismatches, and spew out torrents of warnings when we use a CHAR where
+   a char is expected, or vice versa. We fix these one by one using
+   casts, and the code becomes increasingly ugly. But there remains a
+   serious problem, namely that certain library and kernel functions have
+   arguments that are declared as signed chars (or pointers to them),
+   whereas our character data is unsigned. Fine, we can can use casts
+   here too -- but who knows what happens inside these routines.
+
+   [ [36]Contents ] [ [37]C-Kermit ] [ [38]Kermit Home ]
+    ________________________________________________________________________
+
+  4. MODULES
+
+   When C-Kermit is on the far end of a connection, it is said to be in
+   remote mode. When C-Kermit has made a connection to another computer,
+   it is in local mode. (If C-Kermit is "in the middle" of a multihop
+   connection, it is still in local mode.)
+
+   On another axis, C-Kermit can be in any of several major states:
+
+   Command State
+          Reading and writing from the job's controlling terminal or
+          "console". In this mode, all i/o is handled by the Group E
+          conxxx() (console i/o) routines.
+
+   Protocol State
+          Reading and writing from the communicatons device. In this
+          mode, all i/o is handled by the Group E ttxxx() (terminal i/o)
+          routines.
+
+   Terminal State
+          Reading from the keyboard with conxxx() routines and writing to
+          the communications device with ttxxx() routines AND vice-versa.
+
+   When in local mode, the console and communications device are
+   distinct. During file transfer, Kermit may put up a file-transfer
+   display on the console and sample the console for interruption
+   signals.
+
+   When in remote mode, the console and communications device are the
+   same, and therefore there can be no file-transfer display on the
+   console or interruptions from it (except for "in-band" interruptions
+   such as ^C^C^C).
+
+   [ [39]Contents ] [ [40]C-Kermit ] [ [41]Kermit Home ]
+    ________________________________________________________________________
+
+  4.A. Group A: Library Functions
+
+   Library functions, strictly portable, can be used by all modules on
+   all platforms: [42]ckclib.h, [43]ckclib.c.
+
+   (To be filled in... For now, see [44]Section 3.1 and the comments in
+   ckclib.c.)
+
+   [ [45]Contents ] [ [46]C-Kermit ] [ [47]Kermit Home ]
+    ________________________________________________________________________
+
+  4.B. Group B: Kermit File Transfer
+
+   The Kermit protocol kernel. These files, whose names start with "ckc
+   are supposed to be totally portable C, and are expected to compile
+   correctly on any platform with any C compiler. "Portable" does not
+   mean the same as as "ANSI" -- these modules must compile on 10- and
+   20-year old computers, with C preprocessors, compilers, and/or linkers
+   that have all sorts of restrictions. The Group B modules do not
+   include any header files other than those that come with Kermit
+   itself. They do not contain any library calls except from the standard
+   C library (e.g. printf()). They most certainly do not contain any
+   system calls. Files:
+
+   [48]ckcsym.h
+          For use by C compilers that don't allow -D on the command line.
+
+   [49]ckcasc.h
+          ASCII character symbol definitions.
+
+   [50]ckcsig.h
+          System-independent signal-handling definitions and prototypes.
+
+   [51]ckcdeb.h
+          Originally, debugging definitions. Now this file also contains
+          all definitions and prototypes that are shared by all modules
+          in all groups.
+
+   [52]ckcker.h
+          Kermit protocol symbol definitions.
+
+   [53]ckcxla.h
+          Character-set-related symbol definitions (see next section).
+
+   [54]ckcmai.c
+          The main program. This module contains the declarations of all
+          the protocol-related global variables that are shared among the
+          other modules.
+
+   [55]ckcpro.w
+          The protocol module itself, written in "wart", a lex-like
+          preprocessor that is distributed with Kermit under the name
+          CKWART.C.
+
+   [56]ckcfns.c, [57]ckcfn2.c, [58]ckcfn3.c
+          The protocol support functions used by the protocol module.
+
+   [59]Group B modules may call upon functions from [60]Group E, but not
+   from [61]Group D modules (with the single exception that the main
+   program invokes the user interface, which is in Group D). (This last
+   assertion is really only a conjecture.)
+
+   [ [62]Contents ] [ [63]C-Kermit ] [ [64]Kermit Home ]
+    ________________________________________________________________________
+
+  4.C. Group C: Character-Set Conversion
+
+   Character set translation tables and functions. Used by the [65]Group
+   B, protocol modules, but may be specific to different computers. (So
+   far, all character character sets supported by C-Kermit are supported
+   in [66]ckuxla.c and [67]ckuxla.h, including Macintosh and IBM
+   character sets). These modules should be completely portable, and not
+   rely on any kind of system or library services.
+
+   [68]ckcxla.h
+          Character-set definitions usable by all versions of C-Kermit.
+
+   ck?xla.h
+          Character-set definitions for computer "?", e.g. [69]ckuxla.h
+          for UNIX, [70]ckmxla.h for Macintosh.
+
+   [71]ck?xla
+          Character-set translation tables and functions for computer
+          "?", For example, CKUXLA.C for UNIX, CKMXLA.C for Macintosh. So
+          far, these are the only two such modules. The UNIX module is
+          used for all versions of C-Kermit except the Macintosh version.
+
+   [72]ckcuni.h
+          Unicode definitions
+
+   [73]ckcuni.c
+          Unicode module
+
+   Here's how to add a new file character set in the original
+   (non-Unicode modules). Assuming it is based on the Roman (Latin)
+   alphabet. Let's call it "Barbarian". First, in ck?xla.h, add a
+   definition for FC_BARBA (8 chars maximum length) and increase
+   MAXFCSETS by 1. Then, in ck?xla.c:
+
+     * Add a barbarian entry into the fcsinfo array.
+     * Add a "barbarian" entry to file character set keyword table,
+       fcstab.
+     * Add a "barbarian" entry to terminal character set keyword table,
+       ttcstab.
+     * Add a translation table from Latin-1 to barbarian: yl1ba[].
+     * Add a translation table from barbarian to Latin-1: ybal1[].
+     * Add a translation function from Barbarian to ASCII: xbaas().
+     * Add a translation function from Barbarian to Latin-1: xbal1().
+     * Add a translation function from Latin-1 to Barbarian: xl1ba().
+     * etc etc for each transfer character set...
+     * Add translation function pointers to the xls and xlr tables.
+
+   Other translations involving Barbarian (e.g. from Barbarian to
+   Latin-Cyrillic) are performed through these tables and functions. See
+   ckuxla.h and ckuxla.c for extensive examples.
+
+   To add a new Transfer Character Set, e.g. Latin Alphabet 9 (for the
+   Euro symbol), again in the "old" character-set modules:
+
+   In ckcxla.h:
+
+          + Add a TC_xxxx definition and increase MAXTCSETS accordingly.
+
+   In ck?xla.h (since any transfer charset is also a file charset):
+
+          + Add an FC_xxxx definition and increase MAXFCSETS accordingly.
+
+   In ck?xla.c:
+
+          + Add a tcsinfo[] entry.
+          + Make a tcstab[] keyword table entry.
+          + Make an fcsinfo[] table entry.
+          + Make an fcstab[] keyword table entry.
+          + Make a tcstab[] keyword table entry.
+          + If necessary, make a langinfo[] table entry.
+          + Make entries in the function pointer arrays.
+          + Provide any needed functions.
+
+   As of C-Kermit 7.0, character sets are also handled in parallel by the
+   new (and very large) Unicode module, ckcuni.[ch]. Eventually we should
+   phase out the old way, described just above, and operate entirely in
+   (and through) Unicode. The advantages are many. The disadvantages are
+   size and performance. To add a character to the Unicode modules:
+
+   In ckcuni.h:
+
+          + (To be filled in...)
+
+   In ckcuni.c:
+
+          + (To be filled in...)
+
+   [ [74]Contents ] [ [75]C-Kermit ] [ [76]Kermit Home ]
+    ________________________________________________________________________
+
+  4.D. Group D: User Interface
+
+   This is the code that communicates with the user, gets her commands,
+   informs her of the results. It may be command-line oriented,
+   interactive prompting dialog, menus and arrow keys, windows and mice,
+   speech recognition, telepathy, etc. The one provided is command-and
+   prompt, with the ability to read commands from various sources: the
+   console keyboard, a file, or a macro definition. The user interface
+   has three major functions:
+
+    1. Sets the parameters for the file transfer and then starts it. This
+       is done by setting certain (many) global variables, such as the
+       protocol machine start state, the file specification, file type,
+       communication parameters, packet length, window size, character
+       set, etc.
+    2. Displays messages on the user's screen during the file transfer,
+       using the screen() function, which is called by the group-1
+       modules.
+    3. Executes any commands directly that do not require Kermit
+       protocol, such as the CONNECT command, local file management
+       commands, parameter-setting commands, FTP client commands, etc.
+
+   If you plan to imbed the [77]Group B, files into a program with a
+   different user interface, your interface must supply an appropriate
+   screen() function, plus a couple related ones like chkint() and
+   intmsg() for handling keyboard (or mouse, etc) interruptions during
+   file transfer. The best way to find out about this is to link all the
+   C-Kermit modules together except the ckuu*.o and ckucon.o modules, and
+   see which missing symbols turn up.
+
+   C-Kermit's character-oriented user interface (as opposed to the
+   Macintosh version's graphical user interface) consists of the
+   following modules. C-Kermit can be built with an interactive command
+   parser, a command-line-option-only parser, a graphical user interface,
+   or any combination, and it can even be built with no user interface at
+   all (in which case it runs as a remote-mode Kermit server).
+
+   [78]ckucmd.h
+   [79]ckucmd.c
+          The command parsing primitives used by the interactive command
+          parser to parse keywords, numbers, filenames, etc, and to give
+          help, complete fields, supply defaults, allow abbreviations and
+          editing, etc. This package is totally independent of Kermit,
+          but does depend on the [80]Group E functions.
+
+   [81]ckuusr.h
+          Definitions of symbols used in Kermit's commands.
+
+   ckuus*.c
+          Kermit's interactive command parser, including the script
+          programming language: [82]ckuusr.c (includes top-level keyword
+          tables); [83]ckuus2.c (HELP command text); [84]ckuus3.c (most
+          of the SET command); [85]ckuus4.c (includes variables and
+          functions); ckuus[567].c (miscellaneous);
+
+   [86]ckuusy.c
+          The command-line-option parser.
+
+   [87]ckuusx.c
+          User interface functions common to both the interactive and
+          command-line parsers.
+
+   [88]ckuver.h
+          Version heralds for different implementations.
+
+   [89]ckuscr.c
+          The (old, uucp-like) SCRIPT command
+
+   [90]ckudia.c
+          The DIAL command. Includes specific knowledge of many types of
+          modems.
+
+   Note that none of the above files is actually Unix-specific. Over time
+   they have proven to be portable among all platforms where C-Kermit is
+   built: Unix, VMS, AOS/VS, Amiga, OS-9, VOS, etc etc. Thus the third
+   letter should more properly be "c", but changing it would be too
+   confusing.
+
+   ck?con.c, ckucns.c
+          The CONNECT command. Terminal connection, and in some cases
+          (Macintosh, Windows) also terminal emulation. NOTE: As of
+          C-Kermit 7.0, there are two different CONNECT modules for UNIX:
+          [91]ckucon.c -- the traditional, portable, fork()-based version
+          -- and [92]ckucns.c, a new version that uses select() rather
+          than forks so it can handle encryption. ckucns.c is the
+          preferred version for Unix; ckucon.c is not likely to keep pace
+          with it in terms of upgrades, etc. However, since select() is
+          not portable to every platform, ckucon.c will be kept
+          indefinitely for those platforms that can't use ckucns.c. NOTE:
+          SunLink X.25 support is available only in ckucon.c.
+
+   ck_*.*, ckuat*.*
+          Modules having to do with authentication and encryption. Since
+          the relaxation of USA export laws, they are included with the
+          general source-code distribution. Secure C-Kermit binaries can
+          be built using special targets in the standard makefile.
+          However, secure prebuilt binaries may not be distributed.
+
+   For other implementations, the files may, and probably do, have
+   different names. For example, the Macintosh graphical user interface
+   filenames start with "ckm". Kermit 95 uses the ckucmd and ckuus*
+   modules, but has its own CONNECT command modules. And so on.
+
+   Here is a brief description of C-Kermit's "user interface interface",
+   from ckuusr.c. It is nowhere near complete; in particular, hundreds of
+   global variables are shared among the many modules. These should, some
+   day, be collected into classes or structures that can be passed around
+   as needed; not only for purity's sake, but also to allow for multiple
+   simultaneous communication sessions and or user interfaces. Our list
+   of things to do is endless, and reorganizing the source is almost
+   always at the bottom.
+
+   The ckuus*.c modules (like many of the ckc*.c modules) depend on the
+   existence of C library features like fopen, fgets, feof, (f)printf,
+   argv/argc, etc. Other functions that are likely to vary among
+   operating systems -- like setting terminal modes or interrupts -- are
+   invoked via calls to functions that are defined in the [93]Group E
+   platform-dependent modules, ck?[ft]io.c. The command line parser
+   processes any arguments found on the command line, as passed to main()
+   via argv/argc. The interactive parser uses the facilities of the cmd
+   package (developed for this program, but, in theory, usable by any
+   program). Any command parser may be substituted for this one. The only
+   requirements for the Kermit command parser are these:
+
+    1. Set parameters via global variables like duplex, speed, ttname,
+       etc. See [94]ckcmai.c for the declarations and descriptions of
+       these variables.
+    2. If a command can be executed without the use of Kermit protocol,
+       then execute the command directly and set the sstate (start state)
+       variable to 0. Examples include SET commands, local directory
+       listings, the CONNECT command.
+    3. If a command requires the Kermit protocol, set the following
+       variables:
+ sstate                             string data
+   'x' (enter server mode)            (none)
+   'r' (send a 'get' command)         cmarg, cmarg2
+   'v' (enter receive mode)           cmarg2
+   'g' (send a generic command)       cmarg
+   's' (send files)                   nfils, cmarg & cmarg2 OR cmlist
+   'c' (send a remote host command)   cmarg
+
+       cmlist is an array of pointers to strings.
+       cmarg, cmarg2 are pointers to strings.
+       nfils is an integer (hmmm, probably should be an unsigned long).
+
+        cmarg can be:
+                A filename string (possibly wild), or:
+                a pointer to a prefabricated generic command string, or:
+                a pointer to a host command string.
+
+        cmarg2 is:
+                The name to send a single file under, or:
+                the name under which to store an incoming file; must not
+                be wild.
+                If it's the name for receiving, a null value means to
+                store the file under the name it arrives with.
+
+        cmlist is:
+                A list of nonwild filenames, such as passed via argv.
+
+        nfils is an integer, interpreted as follows:
+                -1: filespec (possibly wild) in cmarg, must be expanded
+                internally.
+                0: send from stdin (standard input).
+                >0: number of files to send, from cmlist.
+
+   The screen() function is used to update the screen during file
+   transfer. The tlog() function writes to a transaction log (if TLOG is
+   defined). The debug() function writes to a debugging log (if DEBUG is
+   defined). The intmsg() and chkint() functions provide the user i/o for
+   interrupting file transfers.
+
+   [ [95]Contents ] [ [96]C-Kermit ] [ [97]Kermit Home ]
+    ________________________________________________________________________
+
+  4.E. Group E: Platform-Dependent I/O
+
+   Platform-dependent function definitions. All the Kermit modules,
+   including the command package, call upon these functions, which are
+   designed to provide system-independent primitives for controlling and
+   manipulating devices and files. For Unix, these functions are defined
+   in the files [98]ckufio.c (files), [99]ckutio.c (communications), and
+   [100]ckusig.c (signal handling).
+
+   For VMS, the files are [101]ckvfio.c, ckvtio.c, and [102]ckusig.c (VMS
+   can use the same signal handling routines as Unix). It doesn't really
+   matter what the files are called, except for Kermit distribution
+   purposes (grouping related files together alphabetically), only that
+   each function is provided with the name indicated, observes the same
+   calling and return conventions, and has the same type.
+
+   The Group E modules contain both functions and global variables that
+   are accessed by modules in the other groups. These are now described.
+
+   (By the way, I got this list by linking all the C-Kermit modules
+   together except ckutio and ckufio. These are the symbols that ld
+   reported as undefined. But that was a long time ago, probably circa
+   Version 6.)
+
+  4.E.1. Global Variables
+
+   char *DELCMD;
+          Pointer to string containing command for deleting files.
+          Example: char *DELCMD = "rm -f "; (UNIX)
+          Example: char *DELCMD = "delete "; (VMS)
+          Note trailing space. Filename is concatenated to end of this
+          string. NOTE: DELCMD is used only in versions that do not
+          provide their own built-in DELETE command.
+
+   char *DIRCMD;
+          Pointer to string containing command for listing files when a
+          filespec is given.
+          Example: char *DIRCMD = "/bin/ls -l "; (UNIX)
+          Example: char *DIRCMD = "directory "; (VMS)
+          Note trailing space. Filename is concatenated to end of this
+          string. NOTE: DIRCMD is used only in versions that do not
+          provide their own built-in DIRECTORY command.
+
+   char *DIRCM2;
+          Pointer to string containing command for listing files when a
+          filespec is not given. (currently not used, handled in another
+          way.)
+          Example: char *DIRCMD2 = "/bin/ls -ld *";
+          NOTE: DIRCMD2 is used only in versions that do not provide
+          their own built-in DIRECTORY command.
+
+   char *PWDCMD;
+          Pointer to string containing command to display current
+          directory.
+          Example: char *PWDCMD = "pwd ";
+          NOTE: PWDCMD is used only in versions that do not provide their
+          own built-in PWD command.
+
+   char *SPACMD;
+          Pointer to command to display free disk space in current
+          device/directory.
+          Example: char *SPACMD = "df .";
+          NOTE: SPACMD is used only in versions that do not provide their
+          own built-in SPACE command.
+
+   char *SPACM2;
+          Pointer to command to display free disk space in another
+          device/directory.
+          Example: char *SPACM2 = "df ";
+          Note trailing space. Device or directory name is added to this
+          string. NOTE: SPACMD2 is used only in versions that do not
+          provide their own built-in SPACE command.
+
+   char *TYPCMD;
+          Pointer to command for displaying the contents of a file.
+          Example: char *TYPCMD = "cat ";
+          Note trailing space. Device or directory name is added to this
+          string. NOTE: TYPCMD is used only in versions that do not
+          provide their own built-in TYPE command.
+
+   char *WHOCMD;
+          Pointer to command for displaying logged-in users.
+          Example: char *WHOCMD = "who ";
+          Note trailing space. Specific user name may be added to this
+          string.
+
+   int backgrd = 0;
+          Flag for whether program is running in foreground (0) or
+          background (nonzero). Background operation implies that screen
+          output should not be done and that all errors should be fatal.
+
+   int ckxech;
+          Flag for who is to echo console typein:
+          1: The program (system is not echoing).
+          0: The OS, front end, terminal, etc (not this program).
+
+   char *ckxsys;
+          Pointer to string that names the computer and operating system.
+          Example: char *ckxsys = " NeXT Mach 1.0";
+          Tells what computer system ckxv applies to. In UNIX Kermit,
+          this variable is also used to print the program herald, and in
+          the SHOW VERSION command.
+
+   char *ckxv;
+          Pointer to version/edit info of ck?tio.c module.
+          Example: char *ckxv = "UNIX Communications Support, 6.0.169, 6
+          Sep 96";
+          Used by SHOW VERSION command.
+
+   char *ckzsys;
+          Like ckxsys, but briefer.
+          Example: char *ckzsys = " 4.3 BSD";
+          Tells what platform ckzv applies to. Used by the SHOW VERSION
+          command.
+
+   char *ckzv;
+          Pointer to version/edit info of ck?fio.c module.
+          Example: char *ckzv = "UNIX File support, 6.0.113, 6 Sep 96";
+          Used by SHOW VERSION command.
+
+   int dfflow;
+          Default flow control. 0 = none, 1 = Xon/Xoff, ... (see FLO_xxx
+          symbols in ckcdeb.h)
+          Set by Group E module. Used by [103]ckcmai.c to initialize flow
+          control variable.
+
+   int dfloc;
+          Default location. 0 = remote, 1 = local. Set by Group E module.
+          Used by ckcmai.c to initialize local variable. Used in various
+          places in the user interface.
+
+   int dfprty;
+          Default parity. 0 = none, 'e' = even, 'o' = odd, 'm' = mark,
+          's' = space. Set by Group E module. Used by ckcmai.c to
+          initialize parity variable.
+
+   char *dftty;
+          Default communication device. Set by Group E module. Used in
+          many places. This variable should be initialized the the symbol
+          CTTNAM, which is defined in ckcdeb.h, e.g. as "/dev/tty" for
+          UNIX, "TT:" for VMS, etc. Example: char *dftty = CTTNAM;
+
+   char *mtchs[];
+          Array of string pointers to filenames that matched the most
+          recent wildcard match, i.e. the most recent call to zxpand().
+          Used (at least) by command parsing package for partial filename
+          completion.
+
+   int tilde_expand;
+          Flag for whether to attempt to expand leading tildes in
+          directory names (used in UNIX only, and then only when the
+          symbol DTILDE is defined.
+
+   int ttnproto;
+          The protocol being used to communicate over a network device.
+          Values are defined in ckcnet.h. Example: NP_TELNET is network
+          protocol "telnet".
+
+   int maxnam;
+          The maximum length for a filename, exclusive of any device or
+          directory information, in the format of the host operating
+          system.
+
+   int maxpath;
+          The maximum length for a fully specified filename, including
+          device designator, directory name, network node name, etc, in
+          the format of the host operating system, and including all
+          punctuation.
+
+   int ttyfd;
+          File descriptor of the communication device. -1 if there is no
+          open or usable connection, including when C-Kermit is in remote
+          mode. Since this is not implemented everywhere, references to
+          it are in #ifdef CK_TTYFD..#endif.
+
+   [ [104]Contents ] [ [105]C-Kermit ] [ [106]Kermit Home ]
+    ________________________________________________________________________
+
+  4.E.2. Functions
+
+   These are divided into three categories: file-related functions (B.1),
+   communication functions (B.2), and miscellaneous functions (B.3).
+
+    4.E.2.1. File-Related Functions
+
+   In most implementations, these are collected together into a module
+   called ck?fio.c, where ? = "u" ([107]ckutio.c for Unix), "v"
+   ([108]ckvtio.c for VMS), [109]etc. To be totally platform-independent,
+   C-Kermit maintains its own file numbers, and provides the functions
+   described in this section to deal with the files associated with them.
+   The file numbers are referred to symbolically, and are defined as
+   follows in ckcker.h:
+
+  #define ZCTERM      0           /* Console terminal */
+  #define ZSTDIO      1           /* Standard input/output */
+  #define ZIFILE      2           /* Current input file for SEND command */
+  #define ZOFILE      3           /* Current output file for RECEIVE command */
+  #define ZDFILE      4           /* Current debugging log file */
+  #define ZTFILE      5           /* Current transaction log file */
+  #define ZPFILE      6           /* Current packet log file */
+  #define ZSFILE      7           /* Current session log file */
+  #define ZSYSFN      8           /* Input from a system function (pipe) */
+  #define ZRFILE      9           /* Local file for READ command */  (NEW)
+  #define ZWFILE     10           /* Local file for WRITE command */ (NEW)
+  #define ZMFILE     11           /* Auxilliary file for internal use */ (NEW)
+  #define ZNFILS     12           /* How many defined file numbers */
+
+   In the descriptions below, fn refers to a filename, and n refers to
+   one of these file numbers. Functions are of type int unless otherwise
+   noted, and are listed mostly alphabetically.
+
+   int
+          chkfn(n) int n;
+          Checks the file number n. Returns:
+           -1: File number n is out of range
+            0: n is in range, but file is not open
+            1: n in range and file is open
+
+   int
+          iswild(filspec) char *filespec;
+          Checks if the file specification is "wild", i.e. contains
+          metacharacters or other notations intended to match multiple
+          filenames. Returns:
+            0: not wild
+            1: wild.
+
+   int
+          isdir(string) char *string;
+          Checks if the string is the name of an existing directory. The
+          idea is to check whether the string can be "cd'd" to, so in
+          some cases (e.g. DOS) it might also indicate any file
+          structured device, such as a disk drive (like A:). Other
+          nonzero returns indicate system-dependent information; e.g. in
+          VMS isdir("[.FOO]") returns 1 but isdir("FOO.DIR;1") returns 2
+          to indicate the directory-file name is in a format that needs
+          conversion before it can be combined with a filename. Returns:
+            0: not a directory (including any kind of error)
+            1: it is an existing directory
+
+   char *
+          zfcdat(name) char *name;
+          Returns modification (preferably, otherwise creation) date/time
+          of file whose name is given in the argument string. Return
+          value is a pointer to a string of the form yyyymmdd hh:mm:ss,
+          for example 19931231 23:59:59, which represents the local time
+          (no timezone or daylight savings time finagling required).
+          Returns the null string ("") on failure. The text pointed to by
+          the string pointer might be in a static buffer, and so should
+          be copied to a safe place by the caller before any subsequent
+          calls to this function.
+
+   struct zfnfp *
+          zfnqfp(fn, buflen, buf) char * fn; int buflen; char * buf;
+          Given the filename fn, the corresponding fully qualified,
+          absolute filename is placed into the buffer buf, whose length
+          is buflen. On failure returns a NULL pointer. On success
+          returns a pointer to a struct zfnfp containing pointers to the
+          full pathname and to just the filename, and an int giving the
+          length of the full pathname. All references to this function in
+          mainline code must be protected by #ifdef ZFNQFP..#endif,
+          because it is not present in all of the ck*fio.c modules. So if
+          you implement this function in a version that did not have it
+          before, be sure to add #define ZFNQFP in the appropriate spot
+          in ckcdeb.h or in the build-procedure CFLAGS.
+
+   int
+          zcmpfn(s1,s2) char * s2, * s2;
+          Compares two filenames to see if they refer to the same.
+          Internally, the arguments can be converted to fully qualified
+          pathnames, e.g. with zfnqfp(), realpath(), or somesuch. In Unix
+          or other systems where symbolic links exist, the link should be
+          resolved before making the comparison or looking at the inodes.
+          Returns:
+            0: Files are not identical.
+            1: Files are identical.
+
+   int
+          zfseek(pos) long pos;
+          Positions the input pointer on the current input file to the
+          given position. The pos argument is 0-based, the offset
+          (distance in bytes) from beginning of the file. Needed for
+          RESEND, PSEND, and other recovery operations. This function is
+          not necessarily possible on all systems, e.g. record-oriented
+          systems. It should only be used on binary files (i.e. files we
+          are sending in binary mode) and stream-oriented file systems.
+          Returns:
+           -1: on failure.
+            0: On success.
+
+   int
+          zchdir(dirnam) char *dirnam;
+          Changes current or default directory to the one given in
+          dirnam. Returns:
+            0: On failure.
+            1: on success.
+
+   long
+          zchki(fn) char *fn;
+          Check to see if file with name fn is a regular, readable,
+          existing file, suitable for Kermit to send -- not a directory,
+          not a symbolic link, etc. Returns:
+           -3: if file exists but is not accessible (e.g.
+          read-protected);
+           -2: if file exists but is not of a readable type (e.g. a
+          directory);
+           -1: on error (e.g. file does not exist, or fn is garbage);
+          >=0: (length of file) if file exists and is readable.
+          Also see isdir(), zgetfs().
+
+   int
+          zchkpid(pid) unsigned long pid;
+          Returns:
+            1: If the given process ID (e.g. pid in UNIX) is valid and
+          active
+            0: otherwise.
+
+   long
+          zgetfs(fn) char *fn;
+          Gets the size of the given file, regardless of accessibility.
+          Used for directory listings. Unlike zchki(), should return the
+          size of any kind of file, even a directory. zgetfs() also
+          should serve as a mini "get file info" function that can be
+          used until we design a better one, by also setting some global
+          variables:
+            int zgfs_link   = 1/0 = file is (not) a symbolic link.
+            int zgfs_dir    = 1/0 = file is (not) a directory.
+            char linkname[] = if zgfs_link != 0, name of file link points
+          to.
+          Returns:
+           -1: on error (e.g. file does not exist, or fn is garbage);
+          >=0: (length of file) if file exists and is readable.
+
+   int
+          zchko(fn) char *fn;
+          Checks to see if a file of the given name can be created.
+          Returns:
+           -1: if file cannot be created, or on any kind of error.
+            0: if file can be created.
+
+   int
+          zchkspa(fn,len) char *f; long len;
+          Checks to see if there is sufficient space to store the file
+          named fn, which is len bytes long. If you can't write a
+          function to do this, then just make a dummy that always returns
+          1; higher level code will recover from disk-full errors. The
+          receiving Kermit uses this function to refuse an incoming file
+          based on its size, via the attribute mechanism. Returns:
+           -1: on error.
+            0: if there is not enough space.
+            1: if there is enough space.
+
+   int
+          zchin(n,c) int n; int *c;
+          Gets a character from file number n, return it in c (call with
+          &c). Returns:
+           -1: on failure, including EOF.
+            0: on success with character in c.
+
+   int
+          zchout(n,c) int n; char c;
+          Writes the character c to file number n. Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          zclose(n) int n;
+          Closes file number n. Returns:
+           -1: on error.
+            1: on success.
+
+   int
+          zdelet(fn) char *name;
+          Attempts to delete (remove, erase) the named file. Returns:
+           -1: on error.
+            1: if file was deleted successfully.
+
+   char *
+          zgperm(char * f)
+          Returns a pointer to the system-dependent numeric
+          permissions/protection string for file f, or NULL upon failure.
+          Used if CK_PERMS is defined.
+
+   char *
+          ziperm(char * f)
+          Returns a pointer to the system-dependent symbolic
+          permissions/protection string for file f, or NULL upon failure.
+          Used if CK_PERMS is defined. Example: In UNIX zgperm(f) might
+          return "100770", but ziperm() might return "-rwxrwx---". In
+          VMS, zgperm() would return a hexadecimal string, but ziperm()
+          would return something like "(RWED,RWED,RE,)".
+
+   char *
+          zgtdir()
+          Returns a pointer to the name of the current directory, folder,
+          etc, or a NULL pointer if the current directory cannot be
+          determined. If possible, the directory specification should be
+          (a) fully specified, e.g. as a complete pathname, and (b) be
+          suitable for appending a filename. Thus, for example, Unix
+          directory names should end with '/'. VMS directory names should
+          look like DEV:[NAME] (rather than, say, NAME.DIR;1).
+
+   char *
+          zhome()
+          Returns a pointer to a string containing the user's home
+          directory, or NULL upon error. Should be formatted like
+          zgtdir() (q.v.).
+
+   int
+          zinfill()
+          Fill buffer from input file. This function is used by the macro
+          zminchar(), which is defined in ckcker.h. zminchar() manages
+          its own buffer, and calls zinfill() to fill it whenever it
+          becomes empty. It is used only for sending files, and reads
+          characters only from file number ZIFILE. zinfill() returns -1
+          upon end of file, -2 upon fatal error, and -3 upon timeout
+          (e.g. when reading from a pipe); otherwise it returns the first
+          character from the buffer it just read.
+
+   int
+          zkself()
+          Kills the current job, session, process, etc, logs out,
+          disappears. Used by the Kermit server when it receives a BYE
+          command. On failure, returns -1. On success, does not return at
+          all! This function should not be called until all other steps
+          have been taken to close files, etc.
+
+   VOID
+          zstrip(fn,&fn2) char *fn1, **fn2;
+          Strips device and directory, etc, from file specification fn,
+          leaving only the filename (including "extension" or "filetype"
+          -- the part after the dot). For example DUA0:[PROGRAMS]OOFA.C;3
+          becomes OOFA.C, or /usr/fdc/oofa.c becomes oofa.c. Returns a
+          pointer to result in fn2.
+
+   int
+          zsetperm(char * file, unsigned int code)
+          Set permissions of file to given system-dependent code.   0: On
+          failure.
+            1: on success.
+
+   int
+          zsetroot(char * dir)
+          Sets the root for the user's file access, like Unix chroot(),
+          but does not require privilege. In Unix, this must be
+          implemented entirely by Kermit's own file access routines.
+          Returns:
+            1: Success
+           -1: Invalid argument
+           -2:
+           -3: Internal error
+           -4: Access to given directory denied
+           -5: New root not within old root
+
+   int
+          zinroot(char * file)
+          If no root is set (zsetroot()), returns 1.
+          Otherwise, if given file is in the root, returns 1.
+          Otherwise, returns 0.
+
+   VOID
+          zltor(fn,fn2) char *fn1, *fn2;
+          Local-To-Remote filename translation. OBSOLETE: replaced by
+          nzltor() (q.v.). Translates the local filename fn into a format
+          suitable for transmission to an arbitrary type of computer, and
+          copies the result into the buffer pointed to by fn2.
+          Translation may involve (a) stripping the device and/or
+          directory/path name, (b) converting lowercase to uppercase, (c)
+          removing spaces and strange characters, or converting them to
+          some innocuous alphabetic character like X, (d) discarding or
+          converting extra periods (there should not be more than one).
+          Does its best. Returns no value. name2 is a pointer to a
+          buffer, furnished by the caller, into which zltor() writes the
+          resulting name. No length checking is done.
+
+   #ifdef NZLTOR
+          VOID
+          nzltor(fn,fn2,convert,pathnames,max) char *fn1,*fn2; int
+          convert,pathnames,max;
+          Replaces zltor(). This new version handles pathnames and checks
+          length. fn1 and fn2 are as in zltor(). This version is called
+          unconditionally for each file, rather than only when filename
+          conversion is enabled. Pathnames can have the following values:
+
+            PATH_OFF: Pathname, if any, is to be stripped
+            PATH_REL: The relative pathname is to be included
+            PATH_ABS: The full pathname is to be included
+
+          After handling pathnames, conversion is done to the result as
+          in the zltor() description if convert != 0; if relative or
+          absolute pathnames are included, they are converted to UNIX
+          format, i.e. with slash (/) as the directory separator. The max
+          parameter specifies the maximum size of fn2. If convert > 0,
+          the regular conversions are done; if convert < 0, minimal
+          conversions are done (we skip uppercasing the letters, we allow
+          more than one period, etc; this can be used when we know our
+          partner is UNIX or similar).
+
+   #endif /* NZLTOR */
+
+   int
+          nzxpand(fn,flags) char *fn; int flags;
+          Replaces zxpand(), which is obsolete as of C-Kermit 7.0.
+          Call with:
+            fn = Pointer to filename or pattern.
+            flags = option bits:
+              flags & ZX_FILONLY  Match regular files
+              flags & ZX_DIRONLY  Match directories
+              flags & ZX_RECURSE  Descend through directory tree
+              flags & ZX_MATCHDOT Match "dot files"
+              flags & ZX_NOBACKUP Don't match "backup files"
+              flags & ZX_NOLINKS  Don't follow symlinks.
+
+          Returns the number of files that match fn, with data structures
+          set up so the first file (if any) will be returned by the next
+          znext() call. If ZX_FILONLY and ZX_DIRONLY are both set, or
+          neither one is set, files and directories are matched. Notes:
+
+         1. It is essential that the number returned by nzxpand() reflect
+            the actual number of filenames that will be returned by
+            znext() calls. In other words:
+  for (n = nzxpand(string,flags); n > 0; n--) {
+      znext(buf);
+      printf("%s\n", buf);
+  }
+            should print all the file names; no more, no less.
+         2. In UNIX, DOS, OS-9, etc, where directories contain entries
+            for themselves (.) and the superior directory (..), these
+            should NOT be included in the list under any circumstances,
+            including when ZX_MATCHDOT is set.
+         3. Additional option bits might be added in the future, e.g. for
+            sorting (sort by date/name/size, reverse/ascending, etc).
+            Currently this is done only in higher level code (through a
+            hack in which the nzxpand() exports its filename array, which
+            is not portable because not all OS's can use this mechanism).
+
+   int
+          zmail(addr,fn) char *addr, fn;
+          Send the local, existing file fn as e-mail to the address addr.
+          Returns:
+            0: on success
+            2: if mail delivered but temp file can't be deleted
+           -2: if mail can't be delivered
+
+   int
+          zmkdir(path) char *path;
+          The path can be a file specification that might contain
+          directory information, in which the filename is expected to be
+          included, or an unambiguous directory specification (e.g. in
+          UNIX it must end with "/"). This routine attempts to create any
+          directories in the given path that don't already exist. Returns
+          0 or greater success: no directories needed creation, or else
+          all directories that needed creation were created successfully;
+          the return code is the number of directories that were created.
+          Returns -1 on failure to create any of the needed directories.
+
+   int
+          zrmdir(path) char *path;
+          Attempts to remove the given directory. Returns 0 on success,
+          -1 on failure. The detailed semantics are open -- should it
+          fail if the directory contains any files or subdirectories,
+          etc. It is probably best for this routine to behave in whatever
+          manner is customary on the underlying platform; e.g. in UNIX,
+          VMS, DOS, etc, where directories can not be removed unless they
+          are empty.
+
+   VOID
+          znewn(fn,s) char *fn, **s;
+          Transforms the name fn into a filename that is guaranteed to be
+          unique. If the file fn does not exist, then the new name is the
+          same as fn; Otherwise, it's different. this function does its
+          best, returns no value. New name is created in caller's space.
+          Call like this: znewn(old,&new);. The second parameter is a
+          pointer to the new name. This pointer is set by znewn() to
+          point to a static string in its own space, so be sure to the
+          result to a safe place before calling this function again.
+
+   int
+          znext(fn) char *fn;
+          Copies the next file name from a file list created by zxpand()
+          into the string pointed to by fn (see zxpand). If no more
+          files, then the null string is placed there. Returns 0 if there
+          are no more filenames, with 0th element the array pointed to by
+          fn set to NUL. If there is a filename, it is stored in the
+          array pointed to by fn and a positive number is returned. NOTE:
+          This is a change from earlier definitions of this function
+          (pre-1999), which returned the number of files remaining; thus
+          0 was the return value when returning the final file. However,
+          no mainline code ever depended on the return value, so this
+          change should be safe.
+
+   int
+          zopeni(n,fn) int n; char *fn;
+          Opens the file named fn for input as file number n. Returns:
+            0: on failure.
+            1: on success.
+
+   int
+          zopeno(n,fn,zz,fcb) int n; char *name; struct zattr *zz; struct
+          filinfo *fcb;
+          Attempts to open the named file for output as file number n. zz
+          is a Kermit file attribute structure as defined in ckcdeb.h,
+          containing various information about the file, including its
+          size, creation date, and so forth. This function should attempt
+          to honor as many of these as possible. fcb is a "file control
+          block" in the traditional sense, defined in ckcdeb.h,
+          containing information relevant to complicated file systems
+          like VMS (RMS), IBM MVS, etc, like blocksize, record length,
+          organization, record format, carriage control, etc. Returns:
+            0: on failure.
+            1: on success.
+
+   int
+          zoutdump()
+          Dumps a file output buffer. Used with the macro zmchout()
+          defined in ckcker.h. Used only with file number ZOFILE, i.e.
+          the file that is being received by Kermit during file transfer.
+          Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          zprint(p,fn) char *p, *f;
+          Prints the file with name fn on a local printer, with options
+          p. Returns:
+            0: on success
+            3: if file sent to printer but can't be deleted
+           -3: if file can't be printed
+
+   int
+          zrename(fn,fn2) char *fn, *fn2;
+          Changes the name of file fn to fn2. If fn2 is the name of an
+          existing directory, or a file-structured device, then file fn
+          is moved to that directory or device, keeping its original
+          name. If fn2 lacks a directory separator when passed to this
+          function, an appropriate one is supplied. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          zcopy(source,dest) char * source, * dest;
+          Copies the source file to the destination. One file only. No
+          wildcards. The destination string may be a filename or a
+          directory name. Returns:
+            0: on success.
+           <0: on failure:
+            -2: source file is not a regular file.
+            -3: source file not found.
+            -4: permission denied.
+            -5: source and destination are the same file.
+            -6: i/o error.
+            -1: other error.
+
+   char *
+          zlocaltime(char *)
+          Call with: "yyyymmdd hh:mm:ss" GMT/UTC date-time. Returns
+          pointer to local date-time string "yyyymmdd hh:mm:ss" on
+          success, NULL on failure.
+
+   VOID
+          zrtol(fn,fn2) char *fn, *fn2;
+          Remote-To-Local filename translation. OBSOLETE: replaced by
+          nzrtol(). Translates a "standard" filename to a local filename.
+          For example, in Unix this function might convert an
+          all-uppercase name to lowercase, but leave lower- or mix-case
+          names alone. Does its best, returns no value. New name is in
+          string pointed to by fn2. No length checking is done.
+
+   #ifdef NZLTOR
+   int
+          nzrtol(fn,fn2,convert,pathnames,max) char *fn1,*fn2; int
+          convert,pathnames,max;
+          Replaces zrtol. Like zrtol but handles pathnames and checks
+          length. See nzltor for detailed description of parameters.
+
+   #endif /* NZLTOR */
+
+   int
+          zsattr(xx) struct zattr *xx;
+          Fills in a Kermit file attribute structure for the file which
+          is to be sent, namely the currently open ZIFILE. Note that this
+          is not a very good design, but we're stuck with it. Callers
+          must ensure that zsattr() is called only on real files, not on
+          pipes, internally generated file-like objects such as server
+          REMOTE command responses, etc. Returns:
+           -1: on failure.
+            0: on success with the structure filled in.
+          If any string member is null, it should be ignored by the
+          caller.
+          If any numeric member is -1, it should be ignored by the
+          caller.
+
+   int
+          zshcmd(s) char *s;
+          s contains to pointer to a command to be executed by the host
+          computer's shell, command parser, or operating system. If the
+          system allows the user to choose from a variety of command
+          processors (shells), then this function should employ the
+          user's preferred shell. If possible, the user's job
+          (environment, process, etc) should be set up to catch keyboard
+          interruption signals to allow the user to halt the system
+          command and return to Kermit. The command must run in ordinary,
+          unprivileged user mode. If possible, this function should
+          return -1 on failure to start the command, or else it should
+          return 1 if the command succeeded and 0 if it failed.
+
+   int
+          pexitstatus
+          zshcmd() and zsyscmd() should set this to the command's actual
+          exit status code if possible.
+
+   int
+          zsyscmd(s) char *s;
+          s contains to pointer to a command to be executed by the host
+          computer's shell, command parser, or operating system. If the
+          system allows the user to choose from a variety of command
+          processors (shells), then this function should employ the
+          system standard shell (e.g. /bin/sh for Unix), so that the
+          results will always be the same for everybody. If possible, the
+          user's job (environment, process, etc) should be set up to
+          catch keyboard interruption signals to allow the user to halt
+          the system command and return to Kermit. The command must run
+          in ordinary, unprivileged user mode. If possible, this function
+          should return -1 on failure to start the command, or else it
+          should return 1 if the command succeeded and 0 if it failed.
+
+   VOID
+          z_exec(s,args) char * s; char * args[];
+          This one executes the command s (which is searched for using
+          the system's normal searching mechanism, such as PATH in UNIX),
+          with the given argument vector, which follows the conventions
+          of UNIX argv[]: the name of the command pointed to by element
+          0, the first arg by element 1, and so on. A null args[] pointer
+          indicates the end of the arugment list. All open files must
+          remain open so the exec'd process can use them. Returns only if
+          unsuccessful.
+
+   int
+          zsinl(n,s,x) int n, x; char *s;
+          Reads a line from file number n. Writes the line into the
+          address s provided by the caller. Writing terminates when
+          newline is read, but with newline discarded. Writing also
+          terminates upon EOF or if length x is exhausted. Returns:
+           -1: on EOF or error.
+            0: on success.
+
+   int
+          zsout(n,s) int n; char *s;
+          Writes the string s out to file number n. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          zsoutl(n,s) int n; char *s;
+          Writes the string s out to file number n and adds a line
+          (record) terminator (boundary) appropriate for the system and
+          the file format. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          zsoutx(n,s,x) int n, x; char *s;
+          Writes exactly x characters from string s to file number n. If
+          s has fewer than x characters, then the entire string s is
+          written. Returns:
+           -1: on failure.
+          >= 0: on success, the number of characters actually written.
+
+   int
+          zstime(fn,yy,x) char *fn; struct zattr *yy; int x;
+          Sets the creation date (and other attributes) of an existing
+          file, or compares a file's creation date with a given date.
+          Call with:
+
+   fn: pointer to name of existing file.
+   yy: Pointer to a Kermit file attribute structure in which yy->date.val
+   is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00, which
+   is to be used for setting or comparing the file date. Other attributes
+   in the struct can also be set, such as the protection/permission (See
+   [110]Appendix I), when it makes sense (e.g. "yy->lprotect.val" can be
+   set if the remote system ID matches the local one).
+    x: A function code: 0 means to set the file's creation date as given.
+   1 means compare the date from the yy struct with the file's date.
+
+          Returns:
+           -1: on any kind of error.
+            0: if x is 0 and the file date was set successfully.
+            0: if x is 1 and date from attribute structure > file
+          creation date.
+            1: if x is 1 and date from attribute structure <= file
+          creation date.
+
+   VOID
+          zstrip(name,name2) char *name, **name2;
+          Strips pathname from filename "name". Constructs the resulting
+          string in a static buffer in its own space and returns a
+          pointer to it in name2. Also strips device name, file version
+          numbers, and other "non-name" material.
+
+   int
+          zxcmd(n,s) char *s;
+          Runs a system command so its output can be accessed as if it
+          were file n. The command is run in ordinary, unprivileged user
+          mode.
+          If n is ZSTDIO or ZCTERM, returns -1.
+          If n is ZIFILE or ZRFILE, then Kermit reads from the command,
+          otherwise Kermit writes to the command.
+          Returns 0 on error, 1 on success.
+
+   int
+          zxpand(fn) char *fn;
+          OBSOLETE: Replaced by nzxpand(), q.v.
+
+   #ifdef ZXREWIND
+   int
+          zxrewind()
+          Returns the number of files returned by the most recent
+          nzxpand() call, and resets the list to the beginning so the
+          next znext() call returns the first file. Returns -1 if zxpand
+          has not yet been called. If this function is available,
+          ZXREWIND should be defined; otherwise it should not be
+          referenced.
+
+   #endif /* ZXREWIND */
+
+   int
+          xsystem(cmd) char *cmd;
+          Executes the system command without redirecting any of its i/o,
+          similar (well, identical) to system() in Unix. But before
+          passing the command to the system, xsystem() ensures that all
+          privileges are turned off, so that the system command executes
+          in ordinary unprivileged user mode. If possible, xsystem()
+          returns the return code of the command that was executed.
+
+    4.E.2.2. IKSD Variables and Functions
+
+   These must be implemented in any C-Kermit version that is to be
+   installed as an Internet Kermit Service Daemon (IKSD). IKSD is
+   expected to be started by the Internet Daemon (e.g. inetd) with its
+   standard i/o redirected to the incoming connection.
+
+   int ckxanon;
+          Nonzero if anonymous logins allowed.
+
+   extern int inserver;
+          Nonzero if started in IKSD mode.
+
+   extern int isguest;
+          Nonzero if IKSD and user logged in anonymously.
+
+   extern char * homdir;
+          Pointer to user's home directory.
+
+   extern char * anonroot;
+          Pointer to file-system root for anonymous users.
+
+   Existing functions must make "if (inserver && isguest)" checks for
+   actions that would not be legal for guests: zdelete(), zrmdir(),
+   zprint(), zmail(), etc.
+
+   int
+          zvuser(name) char * name;
+          Verifies that user "name" exists and is allowed to log in. If
+          the name is "ftp" or "anonymous" and ckxanon != 0, a guest
+          login is set up. Returns 0 if user not allowed to log in,
+          nonzero if user may log in.
+
+   int
+          zvpass(string) char * string;
+          Verifies password of the user from the most recent zvuser()
+          call. Returns nonzero if password is valid for user, 0 if it
+          isn't. Makes any appropriate system log entries (IKSD logins,
+          failed login attempts, etc). If password is valid, logs the
+          user in as herself (if real user), or sets up restricted
+          anonymous access if user is guest (e.g. changes file-system
+          root to anonroot and sets isguest = 1).
+
+   VOID
+          zsyslog()
+          Begins any desired system logging of an IKSD session.
+
+   VOID
+          zvlogout()
+          Terminates an IKSD session. In most cases this is simply a
+          wrapper for exit() or doexit(), with some system logging added.
+
+    4.E.2.3. Privilege Functions
+
+   These functions are used by C-Kermit to adapt itself to operating
+   systems where the program can be made to run in a "privileged" mode,
+   e.g. setuid or setgid in Unix. C-Kermit should NOT read and write
+   files or start subprocesses as a privileged program. This would
+   present a serious threat to system security. The security package has
+   been installed to prevent such security breaches by turning off the
+   program's special privileges at all times except when they are needed.
+
+   In UNIX, the only need Kermit has for privileged status is access to
+   the UUCP lockfile directory, in order to read, create, and destroy
+   lockfiles, and to open communication devices that are normally
+   protected against the user (see the [111]Unix C-Kermit Installation
+   Instructions for discussion). Therefore, privileges should only be
+   enabled for these operations and disabled at all other times. This
+   relieves the programmer of the responsibility of putting expensive and
+   unreliable access checks around every file access and subprocess
+   creation.
+
+   Strictly speaking, these functions are not required in all C-Kermit
+   implementations, because their use (so far, at least) is internal to
+   the Group E modules. However, they should be included in all C-Kermit
+   implementations for operating systems that support the notion of a
+   privileged program (UNIX, RSTS/E, what others?).
+
+   int
+          priv_ini()
+          Determine whether the program is running in privileged status.
+          If so, turn off the privileges, in such a way that they can be
+          turned on again when needed. Called from sysinit() at program
+          startup time. Returns:
+            0 on success
+            nonzero on failure, in which case the program should halt
+          immediately.
+
+   int
+          priv_on()
+          If the program is not privileged, this function does nothing.
+          If the program is privileged, this function returns it to
+          privileged status. priv_ini() must have been called first.
+          Returns:
+            0 on success
+            nonzero on failure
+
+   int
+          priv_off()
+          Turns privileges off (if they are on) in such a way that they
+          can be turned back on again. Returns:
+            0 on success
+            nonzero on failure
+
+   int
+          priv_can()
+          Turns privileges off in such a way that they cannot be turned
+          back on. Returns:
+            0 on success
+            nonzero on failure
+
+   int
+          priv_chk()
+          Attempts to turns privileges off in such a way that they can be
+          turned on again later. Then checks to make sure that they were
+          really turned off. If they were not really turned off, then
+          they are cancelled permanently. Returns:
+            0 on success
+            nonzero on failure
+
+    4.E.2.4. Console-Related Functions
+
+   These relate to the program's "console", or controlling terminal, i.e.
+   the terminal that the user is logged in on and types commands at, or
+   on a PC or workstation, the actual keyboard and screen.
+
+   int
+          conbin(esc) char esc;
+          Puts the console into "binary" mode, so that Kermit's command
+          parser can control echoing and other treatment of characters
+          that the user types. esc is the character that will be used to
+          get Kermit's attention during packet mode; puts this in a
+          global place. Sets the ckxech variable. Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          concb(esc) char esc;
+          Put console in "cbreak" (single-character wakeup) mode. That
+          is, ensure that each console character is available to the
+          program immediately when the user types it. Otherwise just like
+          conbin(). Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          conchk()
+          Returns a number, 0 or greater, the number of characters
+          waiting to be read from the console, i.e. the number of
+          characters that the user has typed that have not been read yet
+          by Kermit.
+
+   long
+          congspd();
+          Returns the speed ("baud rate") of the controlling terminal, if
+          known, otherwise -1L.
+
+   int
+          congks(timo) int timo;
+          Get Keyboard Scancode. Reads a keyboard scan code from the
+          physical console keyboard. If the timo parameter is greater
+          than zero, then times out and returns -2 if no character
+          appears within the given number of seconds. Upon any other kind
+          of error, returns -1. Upon success returns a scan code, which
+          may be any positive integer. For situations where scan codes
+          cannot be read (for example, when an ASCII terminal is used as
+          the job's controlling terminal), this function is identical to
+          coninc(), i.e. it returns an 8-bit character value. congks() is
+          for use with workstations whose keyboards have Alternate,
+          Command, Option, and similar modifier keys, and Function keys
+          that generate codes greater than 255.
+
+   int
+          congm()
+          Console get modes. Gets the current console terminal modes and
+          saves them so that conres() can restore them later. Returns 1
+          if it got the modes OK, 0 if it did nothing (e.g. because
+          Kermit is not connected with any terminal), -1 on error.
+
+   int
+          coninc(timo) int timo;
+          Console Input Character. Reads a character from the console. If
+          the timo parameter is greater than zero, then coninc() times
+          out and returns -2 if no character appears within the given
+          number of seconds. Upon any other kind of error, returns -1.
+          Upon success, returns the character itself, with a value in the
+          range 0-255 decimal.
+
+   VOID
+          conint(f,s) SIGTYP (*f)(), (*s)();
+          Sets the console to generate an interrupt if the user types a
+          keyboard interrupt character, and to transfer control the
+          signal-handling function f. For systems with job control, s is
+          the address of the function that suspends the job. Sets the
+          global variable "backgrd" to zero if Kermit is running in the
+          foreground, and to nonzero if Kermit is running in the
+          background. See ckcdeb.h for the definition of SIGTYP. No
+          return value.
+
+   VOID
+          connoi()
+          Console no interrupts. Disable keyboard interrupts on the
+          console. No return value.
+
+   int
+          conoc(c) char c;
+          Writes character c to the console terminal. Returns:
+          0 on failure, 1 on success.
+
+   int
+          conol(s) char *s;
+          Writes string s to the console. Returns -1 on error, 0 or
+          greater on success.
+
+   int
+          conola(s) char *s[]; {
+          Writes an array of strings to the console. Returns -1 on error,
+          0 or greater on success.
+
+   int
+          conoll(s) char *s;
+          Writes string s to the console, followed by the necessary line
+          termination characters to put the console cursor at the
+          beginning of the next line. Returns -1 on error, 0 or greater
+          on success.
+
+   int
+          conres()
+          Restores the console terminal to the modes obtained by congm().
+          Returns: -1 on error, 0 on success.
+
+   int
+          conxo(x,s) int x; char *s;
+          Write x characters from string s to the console. Returns 0 or
+          greater on success, -1 on error.
+
+   char *
+          conkbg();
+          Returns a pointer to the designator of the console keyboard
+          type. For example, on a PC, this function would return "88",
+          "101", etc. Upon failure, returns a pointer to the empty
+          string.
+
+    4.E.2.5. Communications Functions
+
+   The communication device is the device used for terminal emulation and
+   file transfer. It may or may not be the same device as the console,
+   and it may or may not be a terminal (serial-port) device; it could
+   also be a network connection. For brevity, the communication device is
+   referred to here as the "tty". When the communication device is the
+   same as the console device, Kermit is said to be in remote mode. When
+   the two devices are different, Kermit is in local mode.
+
+   int
+          ttchk()
+          Returns the number of characters that have arrived at the
+          communication device but have not yet been read by ttinc(),
+          ttinl(), and friends. If communication input is buffered (and
+          it should be), this is the sum of the number of unread
+          characters in Kermit's buffer PLUS the number of unread
+          characters in the operating system's internal buffer. The call
+          must be nondestructive and nonblocking, and as inexpensive as
+          possible. Returns:
+            0: or greater on success,
+            0: in case of internal error,
+           -1: or less when it determines the connection has been broken,
+          or there is no connection.
+
+          That is, a negative return from ttchk() should reliably
+          indicate that there is no usable connection. Furthermore,
+          ttchk() should be callable at any time to see if the connection
+          is open. When the connection is open, every effort must be made
+          to ensure that ttchk returns an accurate number of characters
+          waiting to be read, rather than just 0 (no characters) or 1 (1
+          or more characters), as would be the case when we use select().
+          This aspect of ttchk's operation is critical to successful
+          operation of sliding windows and streaming, but "nondestructive
+          buffer peeking" is an obscure operating system feature, and so
+          when it is not available, we have to do it ourselves by
+          managing our own internal buffer at a level below ttinc(),
+          ttinl(), etc, as in the UNIX version (non-FIONREAD case).
+
+          An external global variable, clsondisc, if nonzero, means that
+          if a serial connection drops (carrier on-to-off transition
+          detected by ttchk()), the device should be closed and released
+          automatically.
+
+   int
+          ttclos()
+          Closes the communication device (tty or network). If there were
+          any kind of exclusive access locks connected with the tty,
+          these are released. If the tty has a modem connection, it is
+          hung up. For true tty devices, the original tty device modes
+          are restored. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          ttflui()
+          Flush communications input buffer. If any characters have
+          arrived but have not yet been read, discard these characters.
+          If communications input is buffered by Kermit (and it should
+          be), this function flushes Kermit's buffer as well as the
+          operating system's internal input buffer. Returns:
+           -1: on failure.
+            0: on success.
+
+   int
+          ttfluo()
+          Flush tty output buffer. If any characters have been written
+          but not actually transmitted (e.g. because the system has been
+          flow-controlled), remove them from the system's output buffer.
+          (Note, this function is not actually used, but it is
+          recommended that all C-Kermit programmers add it for future
+          use, even if it is only a dummy function that returns 0
+          always.)
+
+   int
+          ttgmdm()
+          Looks for the modem signals CTS, DSR, and CTS, and returns
+          those that are on in as its return value, in a bit mask as
+          described for ttwmdm, in which a bit is on (1) or off (0)
+          according to whether the corresponding signal is on (asserted)
+          or off (not asserted). Return values:
+           -3: Not implemented
+           -2: if the line does not have modem control
+           -1: on error
+          >=0: on success, with bit mask containing the modem signals.
+
+   long
+          ttgspd()
+          Returns the current tty speed in BITS (not CHARACTERS) per
+          second, or -1 if it is not known or if the tty is really a
+          network, or upon any kind of error. On success, the speed
+          returned is the actual number of bits per second, like 1200,
+          9600, 19200, etc.
+
+   int
+          ttgwsiz()
+          Get terminal window size. Returns -1 on error, 0 if the window
+          size can't be obtained, 1 if the window size has been
+          successfully obtained. Upon success, the external global
+          variables tt_rows and tt_cols are set to the number of screen
+          rows and number of screen columns, respectively. As this
+          function is not implemented in all ck*tio.c modules, calls to
+          it must be wrapped in #ifdef CK_TTGWSIZ..#endif. NOTE: This
+          function must be available to use the TELNET NAWS feature
+          (Negotiate About Window Size) as well as Rlogin.
+
+   int
+          tthang()
+          Hang up the current tty device. For real tty devices, turn off
+          DTR for about 1/3-1/2 second (or other length of time,
+          depending on the system). If the tty is really a network
+          connection, close it. Returns:
+           -1: on failure.
+            0: if it does not even try to hang up.
+            1: if it believes it hung up successfully.
+
+   VOID
+          ttimoff()
+          Turns off all pending timer interrupts.
+
+   int
+          ttinc(timo) int timo; (function is old, return codes are new)
+          Reads one character from the communication device. If timo is
+          greater than zero, wait the given number of seconds and then
+          time out if no character arrives, otherwise wait forever for a
+          character. Returns:
+           -3: internal error (e.g. tty modes set wrong)
+           -2: communications disconnect
+           -1: timeout or other error
+          >=0: the character that was read.
+          It is HIGHLY RECOMMENDED that ttinc() be internally buffered so
+          that calls to it are relatively inexpensive. If it is possible
+          to to implement ttinc() as a macro, all the better, for example
+          something like:
+
+  #define ttinc(t) ( (--txbufn >= 0) ? txbuf[ttbufp++] : txbufr(t) )
+
+          (see description of txbufr() below)
+
+   int
+          ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR
+          *dest, eol, start;
+          ttinl() is Kermit's packet reader. Reads a packet from the
+          communications device, or up to max characters, whichever
+          occurs first. A line is a string of characters starting with
+          the start character up to and including the character given in
+          eol or until the length is exhausted, or, if turn != 0, until
+          the line turnaround character (turn) is read. If turn is 0,
+          ttinl() *should* use the packet length field to detect the end,
+          to allow for the possibility that the eol character appears
+          unprefixed in the packet data. (The turnaround character is for
+          half-duplex linemode connections.)
+
+          If timo is greater than zero, ttinl() times out if the eol
+          character is not encountered within the given number of seconds
+          and returns -1.
+
+          The characters that were input are copied into "dest" with
+          their parity bits stripped if parity is not none. The first
+          character copied into dest should be the start character, and
+          the last should be the final character of the packet (the last
+          block check character). ttinl() should also absorb and discard
+          the eol and turn characters, and any other characters that are
+          waiting to be read, up until the next start character, so that
+          subsequent calls to ttchk() will not succeed simply because
+          there are some terminators still sitting in the buffer that
+          ttinl() didn't read. This operation, if performed, MUST NOT
+          BLOCK (so if it can't be performed in a guaranteed nonblocking
+          way, don't do it).
+
+          On success, ttinl() returns the number of characters read.
+          Optionally, ttinl() can sense the parity of incoming packets.
+          If it does this, then it should set the global variable ttprty
+          accordingly. ttinl() should be coded to be as efficient as
+          possible, since it is at the "inner loop" of packet reception.
+          ttinl() returns:
+           -1: Timeout or other possibly correctable error.
+           -2: Interrupted from keyboard.
+           -3: Uncorrectable i/o error -- connection lost, configuration
+          problem, etc.
+          >=0: on success, the number of characters that were actually
+          read and placed in the dest buffer, not counting the trailing
+          null.
+
+   int
+          ttoc(c) char c;
+          Outputs the character c to the communication line. If the
+          operation fails to complete within two seconds, this function
+          returns -1. Otherwise it returns the number of characters
+          actually written to the tty (0 or 1). This function should only
+          be used for interactive, character-mode operations, like
+          terminal connection, script execution, dialer i/o, where the
+          overhead of the signals and alarms does not create a
+          bottleneck. (THIS DESCRIPTION NEEDS IMPROVEMENT -- If the
+          operation fails within a "certain amount of time"... which
+          might be dependent on the communication method, speed, etc. In
+          particular, flow-control deadlocks must be accounted for and
+          broken out of to prevent the program from hanging indefinitely,
+          etc.)
+
+   int
+          ttol(s,n) int n; char *s;
+          Kermit's packet writer. Writes the n characters of the string
+          pointed to to by s. NOTE: It is ttol's responsibility to write
+          ALL of the characters, not just some of them. Returns:
+           -1: on a possibly correctable error (so it can be retried).
+           -3: on a fatal error, e.g. connection lost.
+          >=0: on success, the actual number of characters written (the
+          specific number is not actually used for anything).
+
+   int
+          ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem,
+          timo;
+          Opens a tty device, if it is not already open. ttopen must
+          check to make sure the SAME device is not already open; if it
+          is, ttopen returns successfully without doing anything. If a
+          DIFFERENT device is currently open, ttopen() must call ttclos()
+          to close it before opening the new one.
+
+        Parameters:
+
+              ttname:
+                      character string - device name or network host
+                      name.
+
+              lcl:
+                      If called with lcl < 0, sets value of lcl as
+                      follows:
+                      0: the terminal named by ttname is the job's
+                      controlling terminal.
+                      1: the terminal named by ttname is not the job's
+                      controlling terminal.
+                      If the device is already open, or if the requested
+                      device can't be opened, then lcl remains (and is
+                      returned as) -1.
+
+              modem:
+                      Less than zero: this is the negative of the network
+                      type, and ttname is a network host name. Network
+                      types (from [112]ckcnet.h:
+
+  NET_TCPB 1   TCP/IP Berkeley (socket)  (implemented in [113]ckutio.c)
+  NET_TCPA 2   TCP/IP AT&T (streams)     (not yet implemented)
+  NET_DEC  3   DECnet                    (not yet implemented)
+
+                      Zero or greater: ttname is a terminal device name.
+                      Zero means a direct connection (don't use modem
+                      signals). Positive means use modem signals
+                      depending on the current setting of ttcarr (see
+                      ttscarr()).
+
+              timo:
+                      > 0: number of seconds to wait for open() to return
+                      before timing out.
+                      <=0: no timer, wait forever (e.g. for incoming
+                      call).
+                      For real tty devices, ttopen() attempts to gain
+                      exclusive access to the tty device, for example in
+                      UNIX by creating a "lockfile" (in other operating
+                      systems, like VMS, exclusive access probably
+                      requires no special action).
+
+        Side effects:
+                Copies its arguments and the tty file descriptor to
+                global variables that are available to the other
+                tty-related functions, with the lcl value altered as
+                described above. Gets all parameters and settings
+                associated with the line and puts them in a global area,
+                so that they can be restored by ttres(), e.g. when the
+                device is closed.
+
+        Returns:
+                  0: on success
+                 -5: if device is in use
+                 -4: if access to device is denied
+                 -3: if access to lock mechanism denied
+                 -2: upon timeout waiting for device to open
+                 -1: on other error
+
+   int
+          ttpkt(speed,flow,parity) long speed; int flow, parity;
+          Puts the currently open tty device into the appropriate modes
+          for transmitting and receiving Kermit packets.
+
+        Arguments:
+
+              speed:
+                      if speed > -1, and the device is a true tty device,
+                      and Kermit is in local mode, ttpkt also sets the
+                      speed.
+
+              flow:
+                      if in the range 0-3, ttpkt selects the
+                      corresponding type of flow control. Currently 0 is
+                      defined as no flow control, 1 is Xon/Xoff, and no
+                      other types are defined. If (and this is a horrible
+                      hack, but it goes back many years and will be hard
+                      to eradicate) flow is 4, then the appropriate tty
+                      modes are set for modem dialing, a special case in
+                      which we talk to a modem-controlled line without
+                      requiring carrier. If flow is 5, then we require
+                      carrier.
+
+              parity:
+                      This is simply copied into a global variable so
+                      that other functions (like ttinl, ttinc, etc) can
+                      use it.
+
+        Side effects:
+                Copies its arguments to global variables, flushes the
+                terminal device input buffer.
+
+        Returns:
+                 -1: on error.
+                  0: on success.
+
+   int
+          ttsetflow(int)
+          Enables the given type of flow control on the open serial
+          communications device immediately. Arguments are the FLO_xxx
+          values from ckcdeb.h, except FLO_DIAL, FLO_DIAX, or FLO_AUTO,
+          which are not actual flow-control types. Returns 0 on success,
+          -1 on failure.
+
+   #ifdef TTSPDLIST
+   long *
+          ttspdlist()
+          Returns a pointer to an array of longs, or NULL on failure. On
+          success, element 0 of the array contains number, n, indicating
+          how many follow. Elements 1-n are serial speeds, expressed in
+          bits per second, that are legal on this platform. The user
+          interface may use this list to construct a menu, keyword table,
+          etc.
+
+   #endif /* TTSPDLIST */
+
+   int
+          ttres()
+          Restores the tty device to the modes and settings that were in
+          effect at the time it was opened (see ttopen). Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          ttruncmd(string) char * string;
+          Runs the given command on the local system, but redirects its
+          input and output to the communication (SET LINE, SET PORT, or
+          SET HOST) device. Returns:
+            0: on failure.
+            1: on success.
+
+   int
+          ttscarr(carrier) int carrier;
+          Copies its argument to a variable that is global to the other
+          tty-related functions, and then returns it. The values for
+          carrier are defined in ckcdeb.h: CAR_ON, CAR_OFF, CAR_AUTO.
+          ttopen(), ttpkt(), and ttvt() use this variable when deciding
+          how to open the tty device and what modes to select. The
+          meanings are these:
+
+   CAR_OFF: Ignore carrier at all times.
+   CAR_ON: Require carrier at all times, except when dialing. This means,
+   for example, that ttopen() could hang forever waiting for carrier if
+   it is not present.
+   CAR_AUTO: If the modem type is zero (i.e. the connection is direct),
+   this is the same as CAR_OFF. If the modem type is positive, then heed
+   carrier during CONNECT (ttvt mode), but ignore it at other times
+   (packet mode, during SET LINE, etc). Compatible with pre-5A versions
+   of C-Kermit. This should be the default carrier mode.
+
+          Kermit's DIAL command ignores the carrier setting, but
+          ttopen(), ttvt(), and ttpkt() all honor the carrier option in
+          effect at the time they are called. None of this applies to
+          remote mode (the tty device is the job's controlling terminal)
+          or to network host connections (modem type is negative).
+
+   int
+          ttsndb()
+          Sends a BREAK signal on the tty device. On a real tty device,
+          send a real BREAK lasting approximately 275 milliseconds. If
+          this is not possible, simulate a BREAK by (for example)
+          dropping down some very low baud rate, like 50, and sending a
+          bunch of null characters. On a network connection, do the
+          appropriate network protocol for BREAK. Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          ttsndlb()
+          Like ttsndb(), but sends a "Long BREAK" (approx 1.5 seconds).
+          For network connections, it is identical to ttsndb().
+          Currently, this function is used only if CK_LBRK is defined (as
+          it is for UNIX and VMS).
+
+   int
+          ttsspd(cps) int cps;
+          For serial devices only, set the device transmission speed to
+          (note carefully) TEN TIMES the argument. The argument is in
+          characters per second, but transmission speeds are in bits per
+          second. cps are used rather than bps because high speeds like
+          38400 are not expressible in a 16-bit int but longs cannot be
+          used because keyword-table values are ints and not longs. If
+          the argument is 7, then the bps is 75, not 70. If the argument
+          is 888, this is a special code for 75/1200 split-speed
+          operation (75 bps out, 1200 bps in). Returns:
+           -1: on error, meaning the requested speed is not valid or
+          available.
+          >=0: on success (don't try to use this value for anything).
+
+   int
+          ttvt(speed,flow) long speed; int flow;
+          Puts the currently open tty device into the appropriate modes
+          for terminal emulation. The arguments are interpreted as in
+          ttpkt(). Side effects: ttvt() stores its arguments in global
+          variables, and sets a flag that it has been called so that
+          subsequent calls can be ignored so long as the arguments are
+          the same as in the last effective call. Other functions, such
+          as ttopen(), ttclose(), ttres(), ttvt(), etc, that change the
+          tty device in any way must unset this flag. In UNIX Kermit,
+          this flag is called tvtflg.
+
+   int
+          ttwmdm(mdmsig,timo) int mdmsig, timo;
+          Waits up to timo seconds for all of the given modem signals to
+          appear. mdmsig is a bit mask, in which a bit is on (1) or off
+          (0) according to whether the corresponding signal is to be
+          waited for. These symbols are defined in ckcdeb.h:
+            BM_CTS (bit 0) means wait for Clear To Send
+            BM_DSR (bit 1) means wait for Data Set Ready
+            BM_DCD (bit 2) means wait for Carrier Detect
+          Returns:
+           -3: Not implemented.
+           -2: This line does not have modem control.
+           -1: Timeout: time limit exceeded before all signals were
+          detected.
+            1: Success.
+
+   int
+          ttxin(n,buf) int n; CHAR *buf;
+          Reads x characters from the tty device into the specified buf,
+          stripping parity if parity is not none. This call waits
+          forever, there is no timeout. This function is designed to be
+          called only when you know that at least x characters are
+          waiting to be read (as determined, for example, by ttchk()).
+          This function should use the same buffer as ttinc().
+
+   int
+          txbufr(timo) int timo;
+          Reads characters into the internal communications input buffer.
+          timo is a timeout interval, in seconds. 0 means no timeout,
+          wait forever. Called by ttinc() (and possibly ttxin() and
+          ttinl()) when the communications input buffer is empty. The
+          buffer should be called ttxbuf[], its length is defined by the
+          symbol TXBUFL. The global variable txbufn is the number of
+          characters available to be read from ttxbuf[], and txbufp is
+          the index of the next character to be read. Should not be
+          called if txbufn > 0, in which case the buffer does not need
+          refilling. This routine returns:
+            -2: Communications disconnect
+            -1: Timeout
+          >=0: A character (0 - 255) On success, the first character that
+          was read, with the variables txbufn and txbufp set
+          appropriately for any remaining characters.
+          NOTE: Currently this routine is used internally only by the
+          UNIX and VMS versions. The aim is to make it available to all
+          versions so there is one single coherent and efficient way of
+          reading from the communications device or network.
+
+    4.E.2.6. Miscellaneous system-dependent functions
+
+   VOID
+          ztime(s) char **s;
+          Returns a pointer, s, to the current date-and-time string in s.
+          This string must be in the fixed-field format associated with
+          the C runtime asctime() function, like: "Sun Sep 16 13:23:45
+          1973\n" so that callers of this function can extract the
+          different fields. The pointer value is filled in by ztime, and
+          the data it points to is not safe, so should be copied to a
+          safe place before use. ztime() has no return value. As a side
+          effect, this routine can also fill in the following two
+          external variables (which must be defined in the
+          system-dependendent modules for each platform):
+            long ztusec: Fraction of seconds of clock time, microseconds.
+            long ztmsec: Fraction of seconds of clock time, milliseconds.
+          If these variables are not set by zstime(), they remain at
+          their initial value of -1L.
+
+   int
+          gtimer()
+          Returns the current value of the elapsed time counter in
+          seconds (see rtimer), or 0 on any kind of error.
+
+   #ifdef GFTIMER
+          CKFLOAT
+          gftimer()
+          Returns the current value of the elapsed time counter in
+          seconds, as a floating point number, capable of representing
+          not only whole seconds, but also the fractional part, to the
+          millisecond or microsecond level, whatever precision is
+          available. Requires a function to get times at subsecond
+          precision, as well as floating-point support. That's why it's
+          #ifdef'd.
+
+   #endif /* GFTIMER */
+
+   int
+          msleep(m) int m;
+          Sleeps (pauses, does nothing) for m milliseconds (a millisecond
+          is one thousandth of a second). Returns:
+           -1: on failure.
+            0: on success.
+
+   VOID
+          rtimer()
+          Sets the elapsed time counter to zero. If you want to time how
+          long an operation takes, call rtimer() when it starts and
+          gtimer when it ends. rtimer() has no return value.
+
+   #ifdef GFTIMER
+          VOID
+          rftimer()
+          Sets the elapsed time counter to zero. If you want to time how
+          long an operation takes, call rftimer() when it starts and
+          gftimer when it ends. rftimer() has no return value. Note:
+          rftimer() is to be used with gftimer() and rtimer() is to be
+          used with gtimer(). See the rftimer() description.
+
+   #endif /* GFTIMER */
+
+   int
+          sysinit()
+          Does whatever needs doing upon program start. In particular, if
+          the program is running in any kind of privileged mode, turns
+          off the privileges (see priv_ini()). Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          syscleanup()
+          Does whatever needs doing upon program exit. Returns:
+           -1: on error.
+            0: on success.
+
+   int
+          psuspend()
+          Suspends the Kermit process, puts it in the background so it
+          can be continued ("foregrounded") later. Returns:
+           -1: if this function is not supported.
+            0: on success.
+
+   [ [114]Contents ] [ [115]C-Kermit ] [ [116]Kermit Home ]
+    ________________________________________________________________________
+
+  4.F. Group F: Network Support
+
+   As of version 5A, C-Kermit includes support for several networks.
+   Originally, this was just worked into the ttopen(), ttclos(), ttinc(),
+   ttinl(), and similar routines in [117]ckutio.c. But this made it
+   impossible to share this code with non-UNIX versions, like VMS,
+   AOS/VS, OS/2, etc. So as of edit 168, network code has been separated
+   out into its own module and header file, ckcnet.c and ckcnet.h:
+
+     [118]ckcnet.h: Network-related symbol definitions.
+     [119]ckcnet.c: Network i/o (TCP/IP, X.25, etc), shared by most
+   platforms.
+     [120]cklnet.c: Network i/o (TCP/IP, X.25, etc) specific to Stratus
+   VOS.
+
+   The routines and variables in these modules fall into two categories:
+
+    1. Support for specific network packages like SunLink X.25 and TGV
+       MultiNet, and:
+    2. support for specific network virtual terminal protocols like CCITT
+       X.3 and TCP/IP Telnet.
+
+   Category (1) functions are analogs to the tt*() functions, and have
+   names like netopen, netclos, nettinc, etc. Group A-D modules do not
+   (and must not) know anything about these functions -- they continue to
+   call the old Group E functions (ttopen, ttinc, etc). Category (2)
+   functions are protocol specific and have names prefixed by a protocol
+   identifier, like tn for telnet x25 for X.25.
+
+   ckcnet.h contains prototypes for all these functions, as well as
+   symbol definitions for network types, protocols, and network- and
+   protocol- specific symbols, as well as #includes for the header files
+   necessary for each network and protocol.
+
+   The following functions are to be provided for networks that do not
+   use normal system i/o (open, read, write, close):
+
+   int
+          netopen()
+          To be called from within ttopen() when a network connection is
+          requested. Calling conventions and purpose same as Group E
+          ttopen().
+
+   int
+          netclos()
+          To be called from within ttclos() when a network connection is
+          being closed. Calling conventions and purpose same as Group E
+          ttclos().
+
+   int
+          nettchk()
+          To be called from within ttchk(). Calling conventions and
+          purpose same as Group E ttchk().
+
+   int
+          netflui()
+          To be called from within ttflui(). Calling conventions and
+          purpose same as Group E ttflui().
+
+   int
+          netbreak()
+          To send a network break (attention) signal. Calling conventions
+          and purpose same as Group E ttsndbrk().
+
+   int
+          netinc()
+          To get a character from the network. Calling conventions same
+          as Group E ttsndbrk().
+
+   int
+          nettoc()
+          Send a "character" (byte) to the network. Calling conventions
+          same as Group E ttoc().
+
+   int
+          nettol()
+          Send a "line" (sequence of bytes) to the network. Calling
+          conventions same as Group E ttol().
+
+   Conceivably, some systems support network connections simply by
+   letting you open a device of a certain name and letting you do i/o to
+   it. Others (like the Berkeley sockets TCP/IP library on UNIX) require
+   you to open the connection in a special way, but then do normal i/o
+   (read, write). In such a case, you would use netopen(), but you would
+   not use nettinc, nettoc, etc.
+
+   VMS TCP/IP products have their own set of functions for all network
+   operations, so in that case the full range of netxxx() functions is
+   used.
+
+   The technique is to put a test in each corresponding ttxxx() function
+   to see if a network connection is active (or is being requested), test
+   for which kind of network it is, and if necessary route the call to
+   the corresponding netxxx() function. The netxxx() function must also
+   contain code to test for the network type, which is available via the
+   global variable ttnet.
+
+   [ [121]Contents ] [ [122]C-Kermit ] [ [123]Kermit Home ]
+      ______________________________________________________________________
+
+    4.F.1. Telnet Protocol
+
+   (This section needs a great deal of updating...)
+
+   As of edit 195, Telnet protocol is split out into its own files, since
+   it can be implemented in remote mode, which does not have a network
+   connection:
+
+      [124]ckctel.h: Telnet protocol symbol definitions.
+      [125]ckctel.c: Telnet protocol.
+
+   The Telnet protocol is supported by the following variables and
+   routines:
+
+   int tn_init
+          Nonzero if telnet protocol initialized, zero otherwise.
+
+   int
+          tn_init()
+          Initialize the telnet protocol (send initial options).
+
+   int
+          tn_sopt()
+          Send a telnet option.
+
+   int
+          tn_doop()
+          Receive and act on a telnet option from the remote.
+
+   int
+          tn_sttyp()
+          Send terminal type using telnet protocol.
+      ______________________________________________________________________
+
+    4.F.2. FTP Protocol
+
+   (To be filled in...)
+      ______________________________________________________________________
+
+    4.F.3. HTTP Protocol
+
+   (To be filled in...)
+      ______________________________________________________________________
+
+    4.F.4. X.25 Networks
+
+   These routines were written SunLink X.25 and have since been adapted
+   to at least on one other: IBM AIXLink/X.25.
+
+   int
+          x25diag()
+          Reads and prints X.25 diagnostics
+
+   int
+          x25oobh()
+          X.25 out of band signal handler
+
+   int
+          x25intr()
+          Sends X.25 interrupt packet
+
+   int
+          x25reset()
+          Resets X.25 virtual circuit
+
+   int
+          x25clear()
+          Clear X.25 virtual circuit
+
+   int
+          x25stat()
+          X.25 status
+
+   int
+          setqbit()
+          Sets X.25 Q-bit
+
+   int
+          resetqbit()
+          Resets X.25 Q-bit
+
+   int
+          x25xin()
+          Reads n characters from X.25 circuit.
+
+   int
+          x25inl()
+          Read a Kermit packet from X.25 circuit.
+
+   [ [126]Contents ] [ [127]C-Kermit ] [ [128]Kermit Home ]
+      ______________________________________________________________________
+
+    4.F.5. Adding New Network Types
+
+   Example: Adding support for IBM X.25 and Hewlett Packard X.25. First,
+   add new network type symbols for each one. There are already some
+   network types defined for other X.25 packages:
+
+  NET_SX25 is the network-type ID for SunLink X.25.
+  NET_VX25 is the network-type ID for VOS X.25.
+
+   So first you should new symbols for the new network types, giving them
+   the next numbers in the sequence, e.g.:
+
+#define NET_HX25 11                     /* Hewlett-Packard X.25 */
+#define NET_IX25 12                     /* IBM X.25 */
+
+   This is in ckcnet.h.
+
+   Then we need symbols to say that we are actually compiling in the code
+   for these platforms. These would be defined on the cc command line:
+
+  -DIBMX25  (for IBM)
+  -DHPX25   (for HP)
+
+   So we can build C-Kermit versions for AIX and HP-UX both with and
+   without X.25 support (since not all AIX and IBM systems have the
+   needed libraries, and so an executable that was linked with them might
+   no load).
+
+   Then in ckcnet.h:
+
+#ifdef IBMX25
+#define ANYX25
+#endif /* IBMX25 */
+
+#ifdef HPX25
+#define ANYX25
+#endif /* HPX25 */
+
+   And then use ANYX25 for code that is common to all of them, and IBMX25
+   or HPX25 for code specific to IBM or HP.
+
+   It might also happen that some code can be shared between two or more
+   of these, but not the others. Suppose, for example, that you write
+   code that applies to both IBM and HP, but not Sun or VOS X.25. Then
+   you add the following definition to ckcnet.h:
+
+#ifndef HPORIBMX25
+#ifdef HPX25
+#define HPORIBMX25
+#else
+#ifdef IBMX25
+#define HPORIBMX25
+#endif /* IBMX25 */
+#endif /* HPX25 */
+#endif /* HPORIBMX25 */
+
+   You can NOT use constructions like "#if defined (HPX25 || IBMX25)";
+   they are not portable.
+
+   [ [129]Contents ] [ [130]C-Kermit ] [ [131]Kermit Home ]
+    ________________________________________________________________________
+
+  4.G. Group G: Formatted Screen Support
+
+   So far, this is used only for the fullscreen local-mode file transfer
+   display. In the future, it might be extended to other uses. The
+   fullscreen display code is in and around the routine screenc() in
+   [132]ckuusx.c.
+
+   In the UNIX version, we use the curses library, plus one call from the
+   termcap library. In other versions (OS/2, VMS, etc) we insert dummy
+   routines that have the same names as curses routines. So far, there
+   are two methods for simulating curses routines:
+
+    1. In VMS, we use the Screen Management Library (SMG), and insert
+       stubs to convert curses calls into SMG calls.
+    2. In OS/2, we use the MYCURSES code, in which the stub routines
+       actually emit the appropriate escape sequences themselves.
+
+   Here are the stub routines:
+
+   int
+          tgetent(char *buf, char *term)
+          Arguments are ignored. Returns 1 if the user has a supported
+          terminal type, 0 otherwise. Sets a global variable (for
+          example, "isvt52" or "isdasher") to indicate the terminal type.
+
+   VOID
+          move(int row, int col)
+          Sends the escape sequence to position the cursor at the
+          indicated row and column. The numbers are 0-based, e.g. the
+          home position is 0,0.
+
+   int
+          clear()
+          Sends the escape sequence to clear the screen.
+
+   int
+          clrtoeol()
+          Sends the escape sequence to clear from the current cursor
+          position to the end of the line.
+
+   In the MYCURSES case, code must be added to each of the last three
+   routines to emit the appropriate escape sequences for a new terminal
+   type.
+
+   clearok(curscr), wrefresh()
+          In real curses, these two calls are required to refresh the
+          screen, for example after it was fractured by a broadcast
+          message. These are useful only if the underlying screen
+          management service keeps a copy of the entire screen, as curses
+          and SMG do. C-Kermit does not do this itself.
+
+   [ [133]Contents ] [ [134]C-Kermit ] [ [135]Kermit Home ]
+    ________________________________________________________________________
+
+  4.H. Group H: Pseudoterminal Support
+
+   (To be filled in...)
+    ________________________________________________________________________
+
+  4.I. Group I: Security
+
+   (To be filled in...)
+
+   [ [136]Contents ] [ [137]C-Kermit ] [ [138]Kermit Home ]
+    ________________________________________________________________________
+
+  APPENDIX I. FILE PERMISSIONS
+
+  I.1. Format of System-Dependent File Permissions in A-Packets
+
+   The format of this field (the "," attribute) is interpreted according
+   to the System ID ("." Attribute).
+
+   For UNIX (System ID = U1), it's the familiar 3-digit octal number, the
+   low-order 9 bits of the filemode: Owner, Group, World, e.g. 660 =
+   read/write access for owner and group, none for world, recorded as a
+   3-digit octal string. High-order UNIX permission bits are not
+   transmitted.
+
+   For VMS (System ID = D7), it's a 4-digit hex string, representing the
+   16-bit file protection WGOS fields (World,Group,Owner,System), in that
+   order (which is the reverse of how they're shown in a directory
+   listing); in each field, Bit 0 = Read, 1 = Write, 2 = Execute, 3 =
+   Delete. A bit value of 0 means permission is granted, 1 means
+   permission is denied. Sample:
+
+  r-01-00-^A/!FWERMIT.EXE'"
+  s-01-00-^AE!Y/amd/watsun/w/fdc/new/wermit.exe.DV
+  r-02-01-^A]"A."D7""B8#119980101 18:14:05!#8531&872960,$A20B-!7(#512@ #.Y
+  s-02-01-^A%"Y.5!
+
+   A VMS directory listing shows the file's protection as (E,RWED,RED,RE)
+   which really means (S=E,O=RWED,G=RED,W=RE), which is reverse order
+   from the internal storage, so (RE,RED,RWED,E). Now translate each
+   letter to its corresponding bit:
+
+  RE=0101, RED=1101, RWED=1111, E=0010
+
+   Now reverse the bits:
+
+  RE=1010, RED=0010, RWED=0000, E=1101
+
+   This gives the 16-bit quantity:
+
+  1010001000001101
+
+   This is the internal representation of the VMS file permission; in
+   hex:
+
+  A20B
+
+   as shown in the sample packet above.
+
+   The VMS format probably would also apply to RSX or any other FILES-11
+   system.
+
+  I.2. Handling of Generic Protection
+
+   To be used when the two systems are different (and/or do not recognize
+   or understand each other's local protection codes).
+
+   First of all, the book is wrong. This should not be the World
+   protection, but the Owner protection. The other fields should be set
+   according to system defaults (e.g. UNIX umask, VMS default protection,
+   etc), except that no non-Owner field should give more permissions than
+   the Owner field.
+
+   [ [139]Top ] [ [140]Contents ] [ [141]C-Kermit Home ] [ [142]Kermit
+   Home ]
+     _________________________________________________________________
+
+
+    C-Kermit Program Logic Manual / [143]The Kermit Project /
+    [144]Columbia University / [145]kermit@columbia.edu / 10 April 2004
+
+References
+
+   1. http://www.columbia.edu/kermit/
+   2. http://www.columbia.edu/
+   3. http://www.columbia.edu/kermit/ckcplm.html
+   4. http://www.columbia.edu/kermit/ckermit.html
+   5. http://www.columbia.edu/kermit/index.html
+   6. http://www.columbia.edu/kermit/ckcplm.html#x1
+   7. http://www.columbia.edu/kermit/ckcplm.html#x2
+   8. http://www.columbia.edu/kermit/ckcplm.html#x3
+   9. http://www.columbia.edu/kermit/ckcplm.html#x4
+  10. http://www.columbia.edu/kermit/ckcplm.html#x4.A
+  11. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+  12. http://www.columbia.edu/kermit/ckcplm.html#x4.C
+  13. http://www.columbia.edu/kermit/ckcplm.html#x4.D
+  14. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+  15. http://www.columbia.edu/kermit/ckcplm.html#x4.F
+  16. http://www.columbia.edu/kermit/ckcplm.html#x4.G
+  17. http://www.columbia.edu/kermit/ckcplm.html#x4.H
+  18. http://www.columbia.edu/kermit/ckcplm.html#x4.I
+  19. http://www.columbia.edu/kermit/ckcplm.html#xa1
+  20. http://www.columbia.edu/kermit/ckcplm.html#contents
+  21. http://www.columbia.edu/kermit/ckcplm.html#contents
+  22. http://www.columbia.edu/kermit/ckermit.html
+  23. http://www.columbia.edu/kermit/index.html
+  24. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+  25. http://www.columbia.edu/kermit/ckcplm.html#contents
+  26. http://www.columbia.edu/kermit/ckermit.html
+  27. http://www.columbia.edu/kermit/index.html
+  28. http://www.columbia.edu/kermit/ckcplm.html#x3.2
+  29. http://www.columbia.edu/kermit/ckcplm.html#contents
+  30. http://www.columbia.edu/kermit/ckermit.html
+  31. http://www.columbia.edu/kermit/index.html
+  32. http://www.columbia.edu/kermit/ckcplm.html#x4.A
+  33. http://www.columbia.edu/kermit/ckcplm.html#contents
+  34. http://www.columbia.edu/kermit/ckermit.html
+  35. http://www.columbia.edu/kermit/index.html
+  36. http://www.columbia.edu/kermit/ckcplm.html#contents
+  37. http://www.columbia.edu/kermit/ckermit.html
+  38. http://www.columbia.edu/kermit/index.html
+  39. http://www.columbia.edu/kermit/ckcplm.html#contents
+  40. http://www.columbia.edu/kermit/ckermit.html
+  41. http://www.columbia.edu/kermit/index.html
+  42. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.h
+  43. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.c
+  44. http://www.columbia.edu/kermit/ckcplm.html#x3.1
+  45. http://www.columbia.edu/kermit/ckcplm.html#contents
+  46. http://www.columbia.edu/kermit/ckermit.html
+  47. http://www.columbia.edu/kermit/index.html
+  48. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsym.h
+  49. ftp://kermit.columbia.edu/kermit/c-kermit/ckcasc.h
+  50. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsig.h
+  51. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+  52. ftp://kermit.columbia.edu/kermit/c-kermit/ckcker.h
+  53. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h
+  54. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+  55. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+  56. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfns.c
+  57. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn2.c
+  58. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn3.c
+  59. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+  60. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+  61. http://www.columbia.edu/kermit/ckcplm.html#x4.D
+  62. http://www.columbia.edu/kermit/ckcplm.html#contents
+  63. http://www.columbia.edu/kermit/ckermit.html
+  64. http://www.columbia.edu/kermit/index.html
+  65. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+  66. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.c
+  67. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h
+  68. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h
+  69. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h
+  70. ftp://kermit.columbia.edu/kermit/c-kermit/ckmxla.h
+  71. ftp://kermit.columbia.edu/kermit/c-kermit/ck?xla
+  72. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.h
+  73. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.c
+  74. http://www.columbia.edu/kermit/ckcplm.html#contents
+  75. http://www.columbia.edu/kermit/ckermit.html
+  76. http://www.columbia.edu/kermit/index.html
+  77. http://www.columbia.edu/kermit/ckcplm.html#x4.B
+  78. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.h
+  79. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.c
+  80. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+  81. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
+  82. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.c
+  83. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus2.c
+  84. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus3.c
+  85. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus4.c
+  86. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusy.c
+  87. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+  88. ftp://kermit.columbia.edu/kermit/c-kermit/ckuver.h
+  89. ftp://kermit.columbia.edu/kermit/c-kermit/ckuscr.c
+  90. ftp://kermit.columbia.edu/kermit/c-kermit/ckudia.c
+  91. ftp://kermit.columbia.edu/kermit/c-kermit/ckucon.c
+  92. ftp://kermit.columbia.edu/kermit/c-kermit/ckucns.c
+  93. http://www.columbia.edu/kermit/ckcplm.html#x4.E
+  94. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+  95. http://www.columbia.edu/kermit/ckcplm.html#contents
+  96. http://www.columbia.edu/kermit/ckermit.html
+  97. http://www.columbia.edu/kermit/index.html
+  98. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+  99. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 100. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c
+ 101. ftp://kermit.columbia.edu/kermit/c-kermit/ckvfio.c
+ 102. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c
+ 103. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 104. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 105. http://www.columbia.edu/kermit/ckermit.html
+ 106. http://www.columbia.edu/kermit/index.html
+ 107. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 108. ftp://kermit.columbia.edu/kermit/c-kermit/ckvtio.c
+ 109. http://www.columbia.edu/kermit/ckcplm.html#x2
+ 110. http://www.columbia.edu/kermit/ckcplm.html#xa1
+ 111. http://www.columbia.edu/kermit/ckuins.html
+ 112. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 113. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 114. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 115. http://www.columbia.edu/kermit/ckermit.html
+ 116. http://www.columbia.edu/kermit/index.html
+ 117. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 118. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
+ 119. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
+ 120. ftp://kermit.columbia.edu/kermit/c-kermit/cklnet.c
+ 121. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 122. http://www.columbia.edu/kermit/ckermit.html
+ 123. http://www.columbia.edu/kermit/index.html
+ 124. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.h
+ 125. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.c
+ 126. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 127. http://www.columbia.edu/kermit/ckermit.html
+ 128. http://www.columbia.edu/kermit/index.html
+ 129. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 130. http://www.columbia.edu/kermit/ckermit.html
+ 131. http://www.columbia.edu/kermit/index.html
+ 132. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
+ 133. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 134. http://www.columbia.edu/kermit/ckermit.html
+ 135. http://www.columbia.edu/kermit/index.html
+ 136. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 137. http://www.columbia.edu/kermit/ckermit.html
+ 138. http://www.columbia.edu/kermit/index.html
+ 139. http://www.columbia.edu/kermit/ckcplm.html#top
+ 140. http://www.columbia.edu/kermit/ckcplm.html#contents
+ 141. http://www.columbia.edu/kermit/ckermit.html
+ 142. http://www.columbia.edu/kermit/index.html
+ 143. http://www.columbia.edu/kermit/index.html
+ 144. http://www.columbia.edu/
+ 145. mailto:kermit@columbia.edu
diff --git a/ckermit-8.0.211/ckcpro.w b/ckermit-8.0.211/ckcpro.w
new file mode 100644
index 0000000..cd9d1fa
--- /dev/null
+++ b/ckermit-8.0.211/ckcpro.w
@@ -0,0 +1,3591 @@
+char *protv =                                                     /* -*-C-*- */
+"C-Kermit Protocol Module 8.0.158, 11 Sep 2002";
+
+int kactive = 0;			/* Kermit protocol is active */
+
+#define PKTZEROHACK
+
+/* C K C P R O  -- C-Kermit Protocol Module, in Wart preprocessor notation. */
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 <os2.h>
+#undef COMMENT
+#endif /* NT */
+#include "ckocon.h"
+#endif /* OS2 */
+
+/*
+ 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, filcnt, carrier, fnspath, interrupted;
+  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 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;
+  extern long speed, ffc, crc16, calibrate, dest;
+#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, filrej;
+    int 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)\n", success ? "OK" : "FAILED");
+		}
+		break;
+	      case 'r':
+	      case 'v':
+		if (rrfspec) {
+		    printf(" RCVD: [%s]",rrfspec);
+		    if (rfspec)
+		      printf(" To: [%s]",rfspec);
+		    printf(" (%s)\n", success ? "OK" : "FAILED");
+		}
+	    }
+	} else if (n > 1) {
+	    switch (myjob) {
+	      case 's':
+		if (sfspec) {
+		    printf(" SENT: (%d files)",n);
+		    if (srfspec)
+		      printf(" Last: [%s]",srfspec);
+		    printf(" (%s)\n", success ? "OK" : "FAILED");
+		}
+		break;
+	      case 'r':
+	      case 'v':
+		if (rrfspec) {
+		    printf(" RCVD: (%d files)",n);
+		    if (rfspec)
+		      printf(" Last: [%s]",rfspec);
+		    printf(" (%s)\n", success ? "OK" : "FAILED");
+		}
+	    }
+	} else if (n == 0) {
+	    if (myjob == 's')
+	      printf(" SENT: (0 files)          \n");
+	    else if (myjob == 'r' || myjob == 'v')
+	      printf(" RCVD: (0 files)          \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. */
+#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 */
+#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: <current-states>input-character { action }
+  nakstate != 0 means we're in a receiving state, in which we send ACKs & NAKs.
+*/
+
+<rgen,get,serve,ropkt>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. */
+
+<ipkt>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,"<ipkt>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,"<ipkt>Y vstate","",vstate);
+	nakstate = 1;			/* Can send NAKs from here. */
+	BEGIN vstate;			/* Switch to desired state */
+    }
+}
+
+<ssopkt>Y {				/* Got ACK to O-Packet */
+    debug(F100,"CPCPRO <ssopkt>Y","",0);
+    x = sopkt();
+    debug(F101,"CPCPRO <ssopkt>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,"<ssopkt>Y winlo","",winlo);
+	nakstate = 1;			/* Can send NAKs from here. */
+	BEGIN vstate;			/* Switch to desired state */
+    }
+    debug(F101,"CPCPRO <ssopkt>Y not changing state","",x);
+}
+
+<ipkt>E {				/* Ignore Error reply to I packet */
+    int x = 0;
+    winlo = 0;				/* Set window-low back to zero */
+    debug(F101,"<ipkt>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,"<ipkt>E winlo","",winlo);
+	winlo = 0;			/* Back to packet 0 again. */
+	nakstate = 1;			/* Can send NAKs from here. */
+	BEGIN vstate;
+    }
+}
+
+<get>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 */
+
+<serve,get>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 */
+}
+
+<serve>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 */
+}
+
+<serve>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 */
+}
+
+<serve>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 */
+}
+
+<serve>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 */
+}
+
+<serve>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 */
+}
+
+<serve>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 <serve>O sgetinit fail","",x);
+	RESUME;
+    } else if (x == 0) {
+	debug(F101,"CKCPRO <serve>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 <serve>O sgetinit TBC","",x);
+	ack();
+	BEGIN ropkt;
+    }
+#endif /* NOSERVER */
+}
+
+<ropkt>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 <ropkt>O sgetinit fail","",x);
+	RESUME;
+    } else if (x == 0) {
+	debug(F101,"CKCPRO <ropkt>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 <ropkt>O sgetinit TBC","",x);
+	ack();
+    }
+#endif /* NOSERVER */
+}
+
+<serve>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 */
+}
+
+<serve>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 */
+}
+
+<serve>q {				/* Interrupted or connection lost */
+    rc = srv_timeout();
+    debug(F101,"srv_timeout","",rc);
+    if (rc > -1) return(rc);		/* (see below) */
+}
+
+<serve>N {				/* Server got a NAK in command-wait */
+#ifndef NOSERVER
+    errpkt((CHAR *)"Did you say RECEIVE instead of GET?");
+    RESUME;
+#endif /* NOSERVER */
+}
+
+<serve>. {				/* 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 */
+}
+
+<generic>I {				/* Login/Out */
+    rc = srv_login();
+    debug(F101,"<generic>I srv_login","",rc);
+    if (rc > -1) return(rc);		/* (see below) */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>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 - Loggin 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 */
+}
+
+<generic>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(NULL)) {
+	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 */
+}
+
+<generic>R {                            /* REMOTE RENAME */
+    rc = srv_rename();
+    debug(F101,"srv_rename","",rc);
+    if (rc > -1) return(rc);		/* (see below) */
+}
+
+<generic>K {                            /* REMOTE COPY */
+    rc = srv_copy();
+    debug(F101,"srv_copy","",rc);
+    if (rc > -1) return(rc);		/* (see below) */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>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 */
+}
+
+<generic>V {				/* Variable query or set */
+    rc = srv_query();
+    debug(F101,"srv_query","",rc);
+    if (rc > -1) return(rc);
+}
+
+<generic>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 */
+}
+
+<generic>. {				/* Anything else in this state... */
+#ifndef NOSERVER
+    errpkt((CHAR *)"Unimplemented REMOTE command"); /* Complain */
+    RESUME;				/* and return to server command wait */
+#endif /* NOSERVER */
+}
+
+<rgen>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 */
+    }
+}
+
+<rgen>Y {				/* Short-Form reply */
+    rc = rcv_shortreply();
+    debug(F101,"<rgen>Y rcv_shortreply","",rc);
+    if (rc > -1) return(rc);
+}
+
+<rgen,rfile>F {				/* File header */
+    /* char *n2; */
+    extern int rsn;
+    debug(F101,"<rfile>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,"<rfile>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 */
+	}
+	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 */
+    }
+}
+
+<rgen,rfile>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 */
+}
+
+<rattr>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 long 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 */
+    }
+}
+
+<rattr>D {				/* First data packet */
+    debug(F100,"<rattr> D firstdata","",0);
+    rc = rcv_firstdata();
+    debug(F101,"rcv_firstdata rc","",rc);
+    if (rc > -1) return(rc);		/* (see below) */
+}
+
+<rfile>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 */
+}
+
+<rdpkt>D {				/* Got Data packet */
+    debug(F101,"<rdpkt>D cxseen","",cxseen);
+    debug(F101,"<rdpkt>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,"<rdpkt>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();
+    }
+}
+
+<rattr>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 */
+    }
+}
+
+<rdpkt>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 */
+}
+
+<rdpkt>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 */
+}
+
+<ssinit>Y {				/* ACK for Send-Init */
+    spar(rdatap);			/* set parameters from it */
+    cancel = 0;
+    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.
+*/
+<ssinit>R {				/* R packet was retransmitted. */
+    xsinit();				/* Resend packet 0 */
+}
+
+<ssinit>G {				/* Same deal if G packet comes again */
+    xsinit();
+}
+
+/* should probably add cases for O, W, V, H, J, ... */
+
+<ssinit>C {				/* Same deal if C packet comes again */
+    xsinit();
+}
+
+<ssfile>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,"<ssfile>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,"<ssfile>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,"<ssfile>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 */
+	}
+    }
+}
+
+<ssattr>Y {				/* Got ACK to A packet */
+    ffc = 0L;				/* Reset file byte counter */
+    debug(F101,"<ssattr>Y cxseen","",cxseen);
+    if (cxseen||czseen) {		/* Interrupted? */
+	debug(F101,"<sattr>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,"<ssattr>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 */
+	}
+    }
+}
+
+<ssdata>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 */
+}
+
+<ssdata>Y {				/* Got ACK to Data packet */
+    canned(rdatap);			/* Check if file transfer cancelled */
+    debug(F111,"<ssdata>Y cxseen",rdatap,cxseen);
+    debug(F111,"<ssdata>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,"<ssdata>Y cxseen","",cxseen);
+	window(1);			/* Set window size back to 1... */
+	if (clsif() < 0)		/* Close input file */
+	  cxseen = 1;			/* Send EOF packet */
+	debug(F101,"<ssdata>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()! */
+}
+
+<sseof>Y {				/* Got ACK to EOF */
+    int g, xdiscard;
+    canned(rdatap);			/* Check if file transfer cancelled */
+    debug(F111,"<sseof>Y cxseen",rdatap,cxseen);
+    debug(F111,"<sseof>Y czseen",rdatap,czseen);
+    debug(F111,"<sseof>Y discard",rdatap,discard);
+    xdiscard = discard;
+    discard = 0;
+    success = (cxseen == 0 && czseen == 0); /* Transfer status... */
+    debug(F101,"<sseof>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,"<sseof>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,"<sseof>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,"<sseof>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 */
+}
+
+<sseot>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 */
+	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;
+    extern int display_demo;
+    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();
+        }
+#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();
+        }
+#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;
+    display_demo = 1;
+#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[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') {
+		if ((int)strlen(s) + (int)strlen(fspec) < tmpbufsiz) {
+		    sprintf(tmpbuf,s,fspec); /* safe (prechecked) */
+		    tlog(F110,"Sending",fspec,0L);
+		}
+	    } else {
+		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
+sgetinit(reget,xget) int reget, xget; {	/* 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 */
diff --git a/ckermit-8.0.211/ckcsig.h b/ckermit-8.0.211/ckcsig.h
new file mode 100644
index 0000000..30fb8bf
--- /dev/null
+++ b/ckermit-8.0.211/ckcsig.h
@@ -0,0 +1,214 @@
+/*  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, 2004,
+    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 <windows.h>
+#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
+__inline int
+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 ttyfd, mdmtyp ;
+    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 ttyfd, mdmtyp;
+    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 */
diff --git a/ckermit-8.0.211/ckcssl.h b/ckermit-8.0.211/ckcssl.h
new file mode 100644
index 0000000..4e31f12
--- /dev/null
+++ b/ckermit-8.0.211/ckcssl.h
@@ -0,0 +1,126 @@
+#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
+#define SSLv3_method                     ck_SSLv3_method
+#define TLSv1_method                     ck_TLSv1_method
+#define SSLv23_client_method             ck_SSLv23_client_method
+#define SSLv3_client_method              ck_SSLv3_client_method
+#define TLSv1_client_method              ck_TLSv1_client_method
+#define SSLv23_server_method             ck_SSLv23_server_method
+#define SSLv3_server_method              ck_SSLv3_server_method
+#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 */
diff --git a/ckermit-8.0.211/ckcsym.h b/ckermit-8.0.211/ckcsym.h
new file mode 100644
index 0000000..c340ca3
--- /dev/null
+++ b/ckermit-8.0.211/ckcsym.h
@@ -0,0 +1,5 @@
+/* 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.
+ */
diff --git a/ckermit-8.0.211/ckctel.c b/ckermit-8.0.211/ckctel.c
new file mode 100644
index 0000000..f743820
--- /dev/null
+++ b/ckermit-8.0.211/ckctel.c
@@ -0,0 +1,8946 @@
+char *cktelv = "Telnet support, 8.0.269, 4 Mar 2004";
+#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, 2004,
+    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 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.
+*/
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+
+#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
+#include <os2.h>
+#undef COMMENT
+#else
+#define isascii __isascii
+#endif /* NT */
+#include "ckocon.h"
+extern int tt_type, max_tt;
+extern struct tt_info_rec tt_info[];
+#endif /* OS2 */
+#endif /* NOTERM */
+
+#ifdef OS2
+#include <assert.h>
+#ifdef NT
+#include <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include <signal.h>
+#include "ckcsig.h"
+#include "ckosyn.h"
+#endif /* OS2 */
+
+#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 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 <signal.h>
+#endif /* UNIX */
+#endif /* CK_NAWS */
+#endif /* NOSIGWINCH */
+#endif /* COMMENT */
+
+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 */
+
+#ifndef TELOPT_MACRO
+int
+telopt_index(opt) int opt; {
+    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
+telopt_ok(opt) int opt; {
+    return((opt >= TELOPT_BINARY && opt <= TELOPT_STDERR) ||
+           (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT) ||
+           (opt == TELOPT_IBM_SAK));
+}
+
+CHAR *
+telopt(opt) int opt; {
+    if (telopt_ok(opt))
+      return((CHAR *)telopts[telopt_index(opt)]);
+    else
+      return((CHAR *)"UNKNOWN");
+}
+
+int
+telopt_mode_ok(opt) int opt; {
+    return((unsigned int)(opt) <= TN_NG_MU);
+}
+
+CHAR *
+telopt_mode(opt) int opt; {
+    if (telopt_mode_ok(opt))
+      return((CHAR *)telopt_modes[opt-TN_NG_RF]);
+    else
+      return((CHAR *)"UNKNOWN");
+}
+#endif /* TELOPT_MACRO */
+
+static int
+tn_outst(notquiet) int notquiet; {
+    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 <timeout> 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 */
+
+    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("<wait for outstanding negotiations>");
+
+#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("<connection closed by peer>");
+            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("<Telnet Option negotiation error>");
+                return(-1);
+              case -2:
+                printf("?Connection closed by peer.\n");
+                if (tn_deb || debses) tn_debug("<Connection closed by peer>");
+		ttclos(0);
+                return(-2);
+              default:
+                if (ch < 0) {
+                  if (tn_deb || debses) tn_debug("<Unknown connection error>");
+                  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(
+                        "<telnet protocol timeout - connection closed>");
+                    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("<Telnet Wait Buffer filled>");
+      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("<no outstanding negotiations>");
+    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 (tn_wait_idx) {
+        hexdump((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
+tn_sopt(cmd,opt) int cmd, opt; {        /* TELNET SEND OPTION */
+    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
+tn_ssbopt(opt,sub,data,len) int opt, sub; CHAR * data; int len; {
+    CHAR buf[256];
+    int n,m,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" : "UNKNOWN" );
+            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,
+                      " <data> 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;
+
+    /* 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.          */
+
+    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)) {
+        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
+
+/*
+ * 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
+
+
+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;
+}
+
+
+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 c, err, dpynum, scrnum, family, sb_len;
+        char *display, *host = NULL, *rest = NULL;
+        unsigned char *sb, *p;
+
+        /* 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 = "<local host name>" */
+                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(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,fwdx_msg_out,"",0);
+    if (tn_deb || debses) tn_debug(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(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,fwdx_msg_out,"",0);
+    if (tn_deb || debses) tn_debug(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<n; j++,i++) {
+        sb_out[i] = FWDX_OPT_NONE;          /* Add zero byte - no options */
+#ifdef COMMENT
+        /* If we had any options to support, this is how we would do it */
+        if ( j == 0 ) {
+            if (opts[j] & FWDX_OPT_XXXX) {
+                /* set flag to remember option is in use */
+                flag = 1;
+                sb_out[i] |= FWDX_OPT_XXXX;
+            }
+        }
+#endif /* COMMENT */
+    }
+    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(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+                  TELOPT(TELOPT_FORWARD_X),
+                  " OPTIONS ",ckctox(sb_out[4],1)," IAC SE",
+                  NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+    }
+#endif /* DEBUG */
+#ifdef OS2
+    RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+    debug(F100,fwdx_msg_out,"",0);
+    if (tn_deb || debses) tn_debug(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
+fwdx_send_options() {
+    int i, 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 */
+    sb_out[i]   = FWDX_OPT_NONE;
+    /* activate options here */
+    i++;
+    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(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ",
+                 TELOPT(TELOPT_FORWARD_X),
+                 " OPTIONS 00 IAC SE",NULL);
+    }
+#endif /* DEBUG */
+#ifdef OS2
+    RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+    debug(F100,fwdx_msg_out,"",0);
+    if (tn_deb || debses) tn_debug(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_data_from_channel(int channel, char * data, int len)
+#else
+fwdx_send_data_from_channel(channel, data, len)
+    int channel; char * data; int len;
+#endif
+{
+    unsigned short nchannel;
+    /* static */ CHAR sb_priv[2048];
+    CHAR * p;
+    int i, j, j_sav, rc;
+    unsigned int tmp;
+
+    debug(F111,"fwdx_send_data_from_channel()","channel",channel);
+
+#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;
+
+    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;
+    j_sav = j;
+
+    for (i = 0; i < len; i++) {
+        tmp = (unsigned int)data[i];
+        if ( tmp == IAC ) {
+            sb_priv[j++] = IAC;
+            sb_priv[j++] = IAC;
+        } else {
+            sb_priv[j++] = tmp;
+        }
+        if ( 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( 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(fwdx_msg_out,TN_MSG_LEN,&sb_priv[j_sav],j-(j_sav+2));
+                ckstrncat(fwdx_msg_out," IAC SE",TN_MSG_LEN);
+            }
+#endif /* DEBUG */
+#ifdef OS2
+            RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+            debug(F100,fwdx_msg_out,"",0);
+            if (tn_deb || debses) tn_debug(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( 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(fwdx_msg_out,TN_MSG_LEN,&sb_priv[6],j-8);
+        ckstrncat(fwdx_msg_out," IAC SE",TN_MSG_LEN);
+    }
+#endif /* DEBUG */
+#ifdef OS2
+    RequestTelnetMutex( SEM_INDEFINITE_WAIT );
+#endif
+#ifdef DEBUG
+    debug(F100,fwdx_msg_out,"",0);
+    if (tn_deb || debses) tn_debug(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);
+}
+
+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;
+}
+
+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 = "<local host name>" */
+            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(fwdx_msg_out,"TELNET SENT SB %s OPTION_DATA XAUTH ",
+                 TELOPT(TELOPT_FORWARD_X));
+        tn_hex(fwdx_msg_out,TN_MSG_LEN,&sb_priv[5],(p-sb_priv)-7);
+        ckstrncat(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,fwdx_msg_out,"",0);
+    if (tn_deb || debses) tn_debug(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: <uint16 name_length> <uint16 data_length> <name> <data>
+ */
+{
+    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(MAXPATHLEN+1);
+    snprintf(fwdx_xauthfile, MAXPATHLEN, "/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;
+
+    if (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);
+            tn_wait_flg = 1;            /* Kermit Option MUST wait */
+            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);
+            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,j;
+        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 (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;
+
+    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 (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 (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);
+      case NP_NONE:
+      case NP_SSL:
+      case NP_TLS:                      /* If not talking to a telnet port, */
+        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);
+      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
+tn_debug(s) char *s; {
+#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
+tn_siks(cmd) int cmd; {         /* TELNET SEND IKS SUB */
+    CHAR buf[8];
+#ifndef NOXFER
+    extern CHAR mystch;                 /* Outgoing Start of Packet Char */
+#else
+    CHAR mystch = '\1';
+#endif /* NOXFER */
+    int n,m,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 c, x, y, n, m, flag;
+    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 ) {
+                int i;
+                ckmakmsg( tn_msg,TN_MSG_LEN,
+                          "TELNET RCVD SB ",TELOPT(opt),
+			  " DATA(buffer-full) ",NULL);
+                tn_hex(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 */
+static char term_buf[64] = { 0, 0 }; /* TERM Environment variable */
+
+#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, m;
+#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 */
+
+
+/* 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 request[6];      /* request it */
+                  sprintf(request,"%cUSER",TEL_ENV_VAR);        /* safe */
+                  tn_ssbopt(TELOPT_NEWENVIRON,TELQUAL_SEND,request,
+                            strlen(request));
+                  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;
+#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)) {
+            hexdump("unknown telnet subnegotiation",sb,n);
+            break;
+        } else if ( !(TELOPT_ME(x) || TELOPT_U(x)) ) {
+            hexdump("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 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(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;
+
+    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];
+    char * reply = 0, * s = 0;
+    int i,j,k,n;                                /* 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 <type> [VAR=0, VALUE=1, ESC=2, USERVAR=3] <value> "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, * s = 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;
+    }
+
+    hexdump((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,"",0) < 0)
+          return(-1);
+        return(0);
+    }
+
+    /* Now construct the real reply */
+
+    n = 0;                              /* Start at beginning of buffer */
+/*
+  Pairs of <type> [VAR=0, VALUE=1, ESC=2, USERVAR=3] <value> "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,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 (!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 [<host>:]<display>[.<screen>]
+     * where <host> is an optional DNS name or ip address with a default of
+     * the localhost; the screen defaults to 0
+     */
+
+    disp = 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 (!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 (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;
+
+    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;
+    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 <text> 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 <value(4)> 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 <value(4)=0> 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 <value(1)> IAC SE */
+    /* Valid <value>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 <value(1)=0> 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 <value(1)> 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 <value(1)=0> 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 <value(1)> 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 <value(1)=0> 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 <value(1)> 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 <value(1)=0> 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 <value(1)> 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 <value(1)=13> 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 <value(1)> 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 <value(1)=4> 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 <value(1)> 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 <value(1)=7> 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 <value(1)> 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 <value(1)=10> 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 <value(1)> 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 <value(1)> 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 <value(1)> 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 */ {
+
+    int rc = -1;
+
+    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);                         /* ZZZzzz */
+            rc = tnc_set_break_state(0);
+        }
+    }
+    debug(F111,"tnsndb","end",rc);
+    return((rc >= 0) ? 0 : -1);
+}
+#endif /* TN_COMPORT */
+#endif /* TNCODE */
diff --git a/ckermit-8.0.211/ckctel.h b/ckermit-8.0.211/ckctel.h
new file mode 100644
index 0000000..c05b3fb
--- /dev/null
+++ b/ckermit-8.0.211/ckctel.h
@@ -0,0 +1,1259 @@
+/* ckctel.h -- Symbol and macro definitions for C-Kermit telnet support */
+
+/*
+  Authors: Jeffrey E Altman <jaltman@secure-endpoints.com>,
+              Secure Endpoints Inc., New York City
+           Frank da Cruz <fdc@columbia.edu>
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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:
+  . Only one source file should include #defines for
+    TELCMDS, TELOPTS, TELOPT_STATES, SLC_NAMES, and AUTH_NAMES.
+  . This file should be used inplace of "arpa/telnet.h"
+*/
+
+#ifndef CKCTEL_H
+#define CKCTEL_H
+#ifdef TNCODE
+/*
+  Definitions for the TELNET protocol.
+  can't rely on library header files for any of them.
+*/
+#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 */
+
+#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]):"UNKNOWN")
+
+/* 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)]:"UNKNOWN")
+#else /* TELOPT_MACRO */
+_PROTOTYP(int telopt_index,(int));
+_PROTOTYP(int telopt_ok,(int));
+_PROTOTYP(CHAR * telopt, (int));
+
+#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]:"UNKNOWN")
+#else /* TELOPT_MACRO */
+_PROTOTYP(int telopt_mode_ok,(int));
+_PROTOTYP(CHAR * telopt_mode,(int));
+
+#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]:"UNKNOWN")
+
+#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 <louisk@microsoft.com> */
+    "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]:"UNKNOWN")
+
+#define AUTHMODE_NAME_OK(x)     ((unsigned int)(x) < AUTHMODE_CNT)
+#define AUTHMODE_NAME(x)      (AUTHMODE_NAME_OK(x)?authmode_names[x]:"UNKNOWN")
+
+/* 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]:"UNKNOWN")
+
+#define ENCTYPE_NAME_OK(x)      ((unsigned int)(x) < ENCTYPE_CNT)
+#define ENCTYPE_NAME(x)      (ENCTYPE_NAME_OK(x)?enctype_names[x]:"UNKNOWN")
+
+/* 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 */
+#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   <stdio.h>
+
+/* 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 */
+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, (VOID));
+_PROTOTYP( int fwdx_server_avail, (VOID));
+#ifdef NT
+_PROTOTYP( VOID fwdx_thread,(VOID *));
+#endif /* NT */
+#endif /* CK_FORWARD_X */
+
+#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)]:"UNKNOWN")
+
+_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 */
diff --git a/ckermit-8.0.211/ckcuni.c b/ckermit-8.0.211/ckcuni.c
new file mode 100644
index 0000000..b579510
--- /dev/null
+++ b/ckermit-8.0.211/ckcuni.c
@@ -0,0 +1,16173 @@
+char * ckcuni = "Unicode support 8.0.115, 9 Oct 2002";
+
+#ifdef OS2
+#define KERMITFONT
+#endif /* OS2 */
+
+/*  C K C U N I . C  --  Unicode/Terminal character-set translations  */
+
+/*
+  Copyright (C) 1999, 2004,
+    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 <fdc@columbia.edu>
+      The Kermit Project, Columbia University, New York City.
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      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"
+
+#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 */
+    "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 <murrays@microsoft.com> 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
+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 */
diff --git a/ckermit-8.0.211/ckcuni.h b/ckermit-8.0.211/ckcuni.h
new file mode 100644
index 0000000..df978c2
--- /dev/null
+++ b/ckermit-8.0.211/ckcuni.h
@@ -0,0 +1,268 @@
+/*  C K C U N I . H  --  Unicode/Terminal character-set translations  */
+
+/*
+  Copyright (C) 1999, 2004,
+    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 <fdc@columbia.edu>
+      The Kermit Project, Columbia University, New York City.
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+*/
+
+/* 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];
+
+_PROTOTYP(int isunicode, (void));
+_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
+_inline
+#else
+_Inline
+#endif /* NT */
+int
+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 */
diff --git a/ckermit-8.0.211/ckcxla.h b/ckermit-8.0.211/ckcxla.h
new file mode 100644
index 0000000..e5dc887
--- /dev/null
+++ b/ckermit-8.0.211/ckcxla.h
@@ -0,0 +1,334 @@
+/*
+  File CKCXLA.H
+
+  System-independent character-set translation header file for C-Kermit.
+*/
+
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  The Kermit Project - Columbia University, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 */
+
+#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 */
diff --git a/ckermit-8.0.211/ckermit.ini b/ckermit-8.0.211/ckermit.ini
new file mode 100644
index 0000000..f007561
--- /dev/null
+++ b/ckermit-8.0.211/ckermit.ini
@@ -0,0 +1,618 @@
+COMMENT - Standard C-Kermit initialization file
+;
+; For C-Kermit Version: 8.0
+;
+; Filename:
+;   .kermrc     (UNIX, OS-9, Aegis)
+;   CKERMIT.INI (OS/2, VMS, OpenVMS, AOS/VS, Atari ST, Commodore Amiga)
+;   ckermit.ini (Stratus VOS)
+;   K95.INI     (Kermit 95 -- but this big version is not used there)
+;   K2.INI      (Kermit/2  -- but ditto)
+;
+; Authors:
+;   Frank da Cruz, Christine M. Gianone, Jeffrey Altman
+;   Columbia University, New York, NY 10025-7799, USA
+;
+; This is the standard and recommended C-Kermit 8.0 initialization file.  To
+; override settings or definitions made in this file, to add new settings or
+; definitions, or to make any other desired customizations, create a separate,
+; personal customization file called:
+;
+;   .mykermrc     (UNIX, OS-9, Aegis, BeBox, Plan 9)
+;   CKERMOD.INI   (OS/2, VMS, OpenVMS, AOS/VS, Atari ST, Commodore Amiga)
+;   ckermod.ini   (VOS)
+;
+; You can also define the customization filename in an environment
+; variable (logical name in VMS), CKERMOD, which takes precedence over
+; the names shown above.
+;
+; WHAT THIS FILE DOES:
+;
+; . Defines your default dialing directory name:
+;     .kdd for UNIX, OS-9 and Aegis; CKERMIT.KDD for other operating systems.
+;        You can override this with the environment variable K_DIAL_DIRECTORY
+; . Defines your default network directory name:
+;     .knd for UNIX, OS-9 and Aegis; CKERMIT.KND for other operating systems.
+;        You can override this with the environment variable K_NET_DIRECTORY
+; . Defines your default services directory name:
+;     .ksd for UNIX, OS-9 and Aegis; CKERMIT.KSD for other operating systems.
+;        You can override this with environment variable K_SERVICE_DIRECTORY.
+; . Defines your customization file name (name given above)
+; . Performs system-dependent setups for UNIX, VMS, OS/2, etc.
+; . Defines VTPRINT macros for use with K95, MS-DOS Kermit, etc.
+; . If you have a services directory, all the macros needed to use it are
+;     defined.  If you don't have a services directory, the macros are not
+;     defined and Kermit starts faster.
+; . Executes your personal customization file, if you have one.
+;   NOTE: Your customization file is NOT executed by Kermit itself; it is
+;   executed by this file.
+;
+; In UNIX, with C-Kermit 7.0 and later, you can store this file with a name
+; other than .kermrc, and it will not be executed automatically, but, if you
+; give this file execute permission, you can execute directly because of the
+; "kerbang line" at the top, whenever you want all of the above actions to
+; occur.  The kerbang line must reflect the actual full path of the Kermit
+; 7.0-or-later executable.
+;
+; C-Kermit 6.0 is documented in the book "Using C-Kermit", 2nd Edition,
+; by Frank da Cruz and Christine M. Gianone, 1997, Digital Press /
+; Butterworth-Heinemann, ISBN 1-55558-164-1.  New features of subsequent
+; versions are documented at the Kermit website:
+; http://www.columbia.edu/kermit/
+;
+; Everything after this point depends on the script programming language.
+; The CHECK command terminates this command file immediately if the script
+; programming language (IF command) is not configured.
+;
+set take error on		; This makes CHECK quit if no script language.
+check if			; Do we have an IF command?  If not, quit now.
+set take error off		; Back to normal.
+
+local _sd _servicedir _xp       ; Declare local variables.
+
+COMMENT - C-Kermit version 6.0 or later required.
+;
+
+asg _xp \v(xprogram)
+if not def _xp asg _xp \v(program)
+if not equal "\m(_xp)" "C-Kermit" -
+  stop 1 \v(cmdfile): This initialization file is only for C-Kermit.
+echo Executing \v(cmdfile) for \v(system)...
+if < \v(version) 60000 -
+  stop 1 \v(cmdfile): C-Kermit 6.0 or later required.
+
+forward \v(system)		; First do system-dependent items...
+
+:unknown			; Should not happen
+Stop 1 Error: System type unknown!
+
+:Aegis				; Apollo Aegis and
+:UNIX				; UNIX, all versions
+asg _myinit -
+  \v(home).mykermrc		; Customization filename
+if remote forward COMMON        ; Skip local-mode items if "-R"
+asg _dialdir -
+  \v(home).kdd			; C-Kermit dialing directory
+asg _netdir -
+  \v(home).knd			; C-Kermit network directory
+asg _servicedir -
+  \v(home).ksd			; C-Kermit services directory
+forward COMMON                  ; End of UNIX section
+
+:OS9/68K			; OS-9
+asg _myinit -
+  \v(home).mykermrc		; Customization filename
+if remote forward COMMON
+asg _dialdir -
+  \v(home).kdd			; C-Kermit dialing directory
+asg _netdir -
+  \v(home).knd			; C-Kermit network directory
+asg _servicedir -
+  \v(home).ksd			; C-Kermit services directory
+else set file display crt
+forward COMMON			; End of OS-9 section
+
+:VMS				; VMS and OpenVMS
+forward COMMON
+
+:OS/2				; Kermit 95
+:WIN32
+echo This initialization file is not for use with K95.
+forward COMMON                  ; End of OS/2 section
+
+:AOS/VS				; Data General AOS/VS
+set window 1			; Sliding windows don't work
+set file char dg-international	; File character-set
+set xfer char latin1		; Transfer character-set
+set file display crt            ; File transfer fisplay
+def cli push			; Escape to CLI
+def reset -			; Macro to reset DG DASHER terminal
+ run write [!ascii 236 306 301]
+forward COMMON                  ; End of AOS/VS section
+
+:Amiga				; Commodore Amiga
+def cls echo \27[H\27[2J	; CLS command to clear the screen
+set file char latin1		; Use Latin Alphabet 1 for file transfer
+set xfer char latin1		; ...
+forward COMMON                  ; End of Amiga section
+
+:Atari_ST			; Atari ST
+def cls echo \27H\27J		; Clear screen a`la VT52
+set server display on		; Show file xfer display in server mode too
+set server timeout 15		; Nonzero required for ^C interruption!
+forward COMMON                  ; End of Atari ST section
+
+:Macintosh			; Apple Macintosh
+set server display on		; Show file xfer display in server mode too.
+forward COMMON
+
+:Stratus_VOS                    ; Stratus VOS
+asg _myinit \v(home)ckermod.ini
+if remote forward COMMON
+asg _dialdir \v(home)ckermit.kdd
+asg _netdir \v(home)ckermit.knd
+asg _servicedir \v(home)ckermit.ksd
+forward COMMON                  ; End of Stratus VOS section
+
+:COMMON				; For all systems
+
+; Define macros that are useful when running C-Kermit in remote mode.
+; These macros serve no purpose on local-mode-only versions such as
+; OS/2, Macintosh, Amiga, and Atari ST Kermit, so we skip defining them
+; for those systems.
+;
+if not = 0 \findex(\v(system),WIN32:OS/2:Macintosh:Amiga:Atari_ST) -
+  forward files
+
+; VTPRINT macro.  Print a file on your PC's local printer.
+
+def VTPRINT echo \27[5i, type \%1, echo \27[4i
+; or if your printer needs a formfeed to force the page out:
+; def VTPRINT  def echo \27[5i, type \%1, echo \12\27[4i
+
+; Macros for host-initiated file transfer using APC:
+;   NOT NEEDED ANY MORE because of autodownload/autoupload.
+;   Remove the following FORWARD command to reinstate these definitions:
+
+:FILES
+
+; Get customization and directory file names.  Environment variables take
+; precedence, so you do not have to edit this file to change these filenames.
+;
+if def \$(CKERMOD) assign _myinit \$(CKERMOD)
+if not def _myinit assign _myinit \v(home)CKERMOD.INI
+
+if remote forward CUSTOM ; Skip all this if -R given on command line
+
+if def \$(K_NET_DIRECTORY) assign _netdir \$(K_NET_DIRECTORY)
+if not def _netdir assign _netdir \v(home)CKERMIT.KND
+
+if def \$(K_DIAL_DIRECTORY) assign _dialdir \$(K_DIAL_DIRECTORY)
+if not def _dialdir assign _dialdir \v(home)CKERMIT.KDD
+
+CHECK DIAL			; Is there a DIAL command?
+xif fail { 			; No.
+    echo DIAL disabled
+    forward CUSTOM
+}
+
+CHECK NETWORK
+xif success {
+    xif exist \m(_netdir) {
+	set net directory \m(_netdir)
+	echo { Network directory is \m(_netdir) }
+    }
+}
+
+if eq "\v(name)" "telnet" forward CUSTOM
+
+xif exist \m(_dialdir) {
+    set dial directory \m(_dialdir)
+    echo { Dial directory is \m(_dialdir) }
+}
+
+COMMENT - Services directory
+
+if def \$(K_SERVICE_DIRECTORY) assign _servicedir \$(K_SERVICE_DIRECTORY)
+if not def _servicedir assign _servicedir \v(home)CKERMIT.KSD
+
+; If no services directory is found skip all the big macro definitions and
+; go straight to the bottom, where we execute the customization file.
+
+if not exist \m(_servicedir) forward custom
+
+echo { Services directory is \m(_servicedir)}
+
+def MAX_SVCS 200               ; Adjust this if you have more entries
+define _sd 0                   ; Assume no services directory
+open read \m(_servicedir)      ; Try to open services directory file
+xif success {
+    declare \&d[\m(MAX_SVCS)]  ; It's open, declare directory array
+    for \%i 1 \m(MAX_SVCS) 1 { ; Read the lines into the array
+	read \&d[\%i]
+	if fail break
+    }
+    close read
+    xif > \%i  \m(MAX_SVCS) {
+	echo Too many entries in services directory
+	echo { Maximum is \m(MAX_SVCS).}
+	echo { Change definition of MAX_SVCS in \v(cmdfile) to allow more. }
+	echo { Services directory disabled.}
+    } else {
+        asg \&d[0] \feval(\%i - 1)
+        define _sd 1
+    }
+}
+
+xif not \m(_sd) {
+    def access echo { Services directory not available.}
+    asg list \m(access)
+} else {
+    def FIND {
+	set case off
+	for \%i 1 \&d[0] 1 {
+	    if eq {\%1} {\fsubstr(\&d[\%i],1,\flen(\%1))} break
+	}
+	if not > \%i \&d[0] return \&d[\%i]
+    }
+    def LIST {
+	xif > \v(argc) 1 {
+	    do find \%1
+	    if def \v(return) echo \v(return)
+	    else echo \%1: Not found
+	} else {
+	    echo \&d[0] items in services directory:
+	    for \%i 1 \&d[0] 1 { echo \fcont(\&d[\%i]) }
+	}
+    }
+    def SPLIT { asg _word1 \%1, asg _word2 \%2 }
+    def DOACCESS {               ; (Used internally by ACCESS macro)
+	do \%5 \%6 \%7 \%8 \%9   ; Do the connection macro
+	if fail end 1
+        split \%3                ; Get words from \%3
+	asg \%3 \m(_word1)
+	asg \%2 \m(_word2)
+	do \%3 \%4 {\%1} \%2     ; Login macro, userid, password, prompt
+    }
+    def ACCESS {
+	if not defined \%1 end 1 access what?        ; Check service
+	do find \%1                                  ; Look it up
+	if success doaccess {\%2} \v(return)         ; OK, try it
+	else end 1 "\%1" not in services directory   ; Not found
+	if fail end 1                                ; DOACCESS failed?
+	xif eq \v(cmdlevel) 1 {
+	    echo
+	    echo ACCESS: Login succeeded - CONNECTing...
+            show escape
+            output \13
+	    connect /quietly
+        }
+    }
+}
+
+:CONNECTION ; Macros for making connections
+
+COMMENT - SERIAL macro.  Arguments:
+; \%1 = device name
+; \%2 = speed
+;
+def SERIAL {
+    if < \v(argc) 3                         ; All arguments given?
+      end 1 Usage: SERIAL device speed      ; No.
+    set line \%1                            ; OK, try to SET LINE.
+    if failure -                            ; If this failed,
+      end 1 Can't open device: \%1          ; print message and quit.
+    set speed \%2                           ; Try to set the speed.
+    if fail end 1 Unsupported speed: \%2    ; Failed.
+    echo Connection successful.             ; Succeeded.
+}
+
+COMMENT - NET macro.  Arguments:
+; \%1 = network type
+; \%2 = host name or address
+;
+def NET {
+    if < \v(argc) 3 end 1 Usage: NET network host
+    set network type \%1
+    if fail end 1 unsupported network: \%1
+    set login user                ; Don't send user ID.
+    set host \%2
+    if fail end 1 Can't reach host: \%2
+    echo Connection successful.
+}
+
+COMMENT - CALL macro.  Arguments:
+;
+; \%1 = modem type
+; \%2 = device name
+; \%3 = speed
+; \%4 = phone number
+;
+def CALL {
+    if < \v(argc) 5 -         ; All arguments present?
+      end 1 Usage: CALL modem device speed number
+    xif not equal {\v(modem)} {\%1} { ; Set modem type
+        set modem \%1
+        if fail end 1 unknown modem type: \%1
+    }
+    xif not equal {\v(line)} {\%2} { ; Communication device
+        set line \%2
+        if fail end 1 can't open device: \%2
+    }
+    xif not equal {\v(speed)} {\%3} { ; Communication speed
+        set speed \%3
+        if fail end 1 unsupported speed: \%3
+    }
+    dial \%4                  ; Dial the number
+    if fail end 1 Can't place call: \%4
+    end 0 Connection successful.
+}
+
+COMMENT - TCPCALL macro.  Arguments:
+;
+; \%1 = server name:port
+; \%2 = modem type
+; \%3 = phone number
+;
+def TCPCALL {
+    if < \v(argc) 4 -         ; All arguments present?
+      end 1 Usage: TCPCALL server[:port] modem number
+    set net type tcp/ip       ; Which network to use
+    if fail end 1 unsupported network: tcp/ip
+    set host \%1              ; Access server and port
+    if fail end 1 can't access server \%1
+    set modem \%2             ; Set modem type
+    if fail end 1 unknown modem type: \%2
+    dial \%3                  ; Dial the number
+    if fail end 1 Can't place call: \%3
+    end 0 Connection successful.
+}
+
+COMMENT - SPRINT macro.  Arguments:
+; \%1 = Service name or address
+;
+def SPRINT {
+    if < \v(argc) 2 end 1 Usage: \%0 service
+    set input timeout proceed
+    output @D\13
+    input 10 TERMINAL=
+    if fail end 1 No terminal prompt
+    out D1\13
+    inp 10 @
+    if fail end 1 No atsign prompt
+    output c \%1\13
+    input 10 CONNECTED
+    if fail end 1 Can't access \%1 from SprintNet
+}
+
+COMMENT - ULOGIN macro.  For logging into systems where user ID is required
+; but there is no password.  Arguments:
+; \%1 = UNIX user ID
+;
+define ULOGIN {
+    if < \v(argc) 2 end 1 Usage: \%0 userid
+    set input timeout proceed     ; Handle timeouts ourselves
+    set case on                   ; Case is important in UNIX
+    minput 5 login: Username: {User ID:} {User Name:}
+    out \%1\13                    ; Send username, carriage return
+    end 0
+}
+
+COMMENT - VMSLOGIN macro.  Arguments:
+; \%1 = VMS user ID
+; \%2 = Password.  If password not supplied, it is prompted for.
+; \%3 = System prompt.  If omitted a default is supplied.
+;
+define VMSLOGIN {
+    if < \v(argc) 2 end 1 Usage: \%0 userid [ password [ prompt ] ]
+    while not defined \%2 {
+        askq \%2 { \%1's password: }
+    }
+    set parity none               ; Set communication parameters
+    set duplex full
+    set handshake none
+    set input timeout proceed     ; Handle timeouts ourselves
+    in 5 Username:                ; Is prompt already there?
+    xif fail {                    ; No.
+        for \%i 1 3 1 {           ; Try 3 times to get it.
+            out \13               ; Send carriage return
+            in 5 Username:        ; Look for prompt
+            if success break      ; Success, go log in
+        }
+        if > \%i 3 end 1 No Username prompt
+    }
+    out \%1\13                    ; Send username, carriage return
+    inp 5 Password:               ; Wait 5 sec for this prompt
+    if fail end 1 No password prompt
+    pause                         ; Wait a sec
+    out \%2\13                    ; Send password
+    xif not emulation {           ; No emulator built in?
+        set input echo off        ; Protect terminal from this
+        minput 10 {\27Z} {\27[c} {\27[0c} ; Get terminal ID query
+        xif success {                     ; Got one
+            output \27[\?1c               ; Send VT100 terminal ID
+            in 2 \27[6n                   ; Screen dimension query?
+            if succ out \27[\v(rows);\v(cols)R ; Send dimensions
+        }
+        set input echo on         ; Echo input again
+    }
+    if not def \%3 -              ; If we were not given a prompt
+      asg \%3 {\v(prompt)}        ; use the SET LOGIN PROMPT value
+    if not def \%3 -              ; If we still don't have a prompt
+      asg \%3 {\13$\32}           ; use this one as the default
+    reinp 0 \%3                   ; Did we INPUT the prompt already?
+    if fail inp 60 \%3            ; No, look now.
+    if fail end 1
+}
+
+COMMENT - UNIXLOGIN macro.  Arguments:
+; \%1 = UNIX user ID
+; \%2 = Password.  If password not supplied, it is prompted for.
+; \%3 = System prompt.  If omitted a default is supplied.
+;
+define UNIXLOGIN {
+    local \%m \%i
+    if < \v(argc) 2 -
+      end 1 Usage: \%0 userid [ password [ prompt ] ]
+    while not defined \%2 {
+        askq \%2 { \%1's password: }
+    }
+    set input echo on
+    set parity none               ; Set communication parameters.
+    set duplex full
+    set handshake none
+    set input timeout proceed     ; Handle timeouts ourselves
+    set case on                   ; Case is important in UNIX
+    def \%m 10                    ; Waiting time for INPUT
+    for \%i 1 5 1 {
+        minput \%m login: {ssword:} {Password for \%1:}
+	if success break
+	output \B\13
+        \%m ::= 6-\%1
+    }
+    if > \%i 5 end 1 {No response from host}
+    xif = \v(minput) 1 {	  ; Have username prompt
+	output \%1\13		  ; Send username
+        minput 5 {ssword:} {ssword for \%1:} ; Wait for password prompt
+	if fail end 1 {No password prompt}
+    }
+    pause                         ; Wait a sec
+    out \%2\13                    ; Send password
+    if not def \%3 -              ; If we were not given a prompt
+      asg \%3 {\v(prompt)}        ; use the SET LOGIN PROMPT value
+    if not def \%3 -              ; If we still don't have a prompt
+      asg \%3 {\10$ }             ; use this one as the default
+    reinp 0 \%3                   ; Did we INPUT the prompt already?
+    if fail inp 60 \%3            ; No, look now.
+    if fail end 1
+}
+
+COMMENT - VMLINELOGIN macro.  Arguments:
+; \%1 = User ID
+; \%2 = Password
+;
+define VMLINELOGIN {
+    if < \v(argc) 2 -
+      end 1 Usage: \%0 userid [ password ]
+    while not defined \%2 {
+        askq \%2 { \%1's password: }
+    }
+    set parity mark               ; Set communication parameters
+    set flow none
+    set handshake xon
+    set duplex half
+    set input timeout quit        ; Don't bother with IF FAILURE
+    input 10 BREAK KEY            ; Look for BREAK KEY prompt
+    pause 1                       ; Wait a second
+    output \B                     ; Send BREAK
+    input 10 .\17, output logon \%1\13    ; Now log in
+    input 10 .\17, output \%2\13          ; Send password
+    input 10 .\17, output \13             ; Send carriage return
+    input 10 .\17, output \13             ; Send another one
+    end 0
+}
+
+COMMENT - VMFULLOGIN macro.  Arguments:
+; \%1 = User ID
+; \%2 = Password
+;
+define VMFULLOGIN {
+    if < \v(argc) 2 -
+      end 1 Usage: \%0 userid [ password ]
+    while not defined \%2 {
+        askq \%2 { \%1's password: }
+    }
+    set input timeout quit      ; Quit if INPUT fails
+    set parity even             ; Set communication parameters
+    set duplex full
+    set handshake none
+    set flow xon/xoff
+    out \13                     ; Send carriage return
+    inp 5 TERMINAL TYPE:        ; Get terminal-type prompt
+    out vt-100\13               ; Just send "vt-100"
+    inp 20 RUNNING              ; Get RUNNING message
+    pau 1                       ; Wait one second
+    out \%1\9\%2\13             ; Send user ID, tab, password
+    out \13\13                  ; Two more carriage returns
+    end 0
+}
+
+COMMENT - CISLOGIN macro.  Arguments:
+; \%1 = CompuServe User ID
+; \%2 = Password
+; \%3 = Prompt
+;
+define CISLOGIN {
+    if < \v(argc) 2 -
+      end 1 Usage: \%0 userid [ password [ prompt ] ]
+    while not defined \%2 {
+        askq \%2 { \%1's password: }
+    }
+    set terminal bytesize 7     ; No 8-bit characters
+    set input timeout quit      ; Skip the IF FAILURE's
+    output \13                  ; Send initial carriage return
+    input 5 Host Name:          ; Look for Host Name prompt
+    output cis\13               ; Send "cis" and carriage return
+    input 5 User ID:            ; Look for User ID prompt
+    output \%1\13               ; Send ID and carriage return
+    input Password:             ; Look for Password prompt
+    output \%2\13               ; Send password and CR
+    if not def \%3 asg \%3 \v(prompt)
+    if not def \%3 asg \%3 {CompuServe Information Service}
+    input 30 \%3
+    end 0
+}
+
+COMMENT - DOWLOGIN macro.  Arguments:
+; \%1 = Dow Jones Password
+;
+define DOWLOGIN {
+    while not defined \%1 {              ; Get password
+        askq \%1 { Dow Jones password: }
+    }
+    set input timeout proceed
+    input 20 SERVICE PLEASE\?\?\?\?      ; Look for Dow prompt
+    if fail end 1 No service prompt
+    out djnr\13                          ; Select DJNR
+    input 10 @@@@@@@@                        ; Get password prompt
+    if fail end 1 No password prompt
+    pause 1                              ; Wait a second, then...
+    output \%1\13                        ; send password and CR
+    input 30 ENTER QUERY                 ; Get DJNR query prompt
+    if fail end 1 No main query prompt
+    pause 1
+}
+
+COMMENT - DJNRSPRINT macro: Log in to Dow Jones via SprintNet.
+;
+def djnrsprint sprint dow, if success dowlogin
+
+COMMENT - NOLOGIN macro.  Does nothing.  Use when login not required.
+;
+def nologin comment
+
+:CUSTOM ; Customization file
+
+; In VMS and OpenVMS, allow for system-wide site customizations
+
+xif equal "\v(system)" "VMS" {
+    xif exist CKERMIT_INI:CKERMIT.SYS {
+	echo Executing CKERMIT_INI:CKERMIT.SYS
+	take CKERMIT_INI:CKERMIT.SYS
+    }
+}
+
+; Execute user's personal customization file
+
+xif exist \m(_myinit)  {		; If it exists,
+    echo Executing \m(_myinit)...	; print message,
+    take \m(_myinit)			; and TAKE the file.
+}
+
+; Finish up with traditional greeting.
+
+if < \v(ntime) 43200 echo Good Morning!
+  else if < \v(ntime) 61200 echo Good Afternoon!
+  else echo Good Evening.
+
+End ; of C-Kermit 8.0 initialization file.
diff --git a/ckermit-8.0.211/ckermit70.txt b/ckermit-8.0.211/ckermit70.txt
new file mode 100644
index 0000000..8aca397
--- /dev/null
+++ b/ckermit-8.0.211/ckermit70.txt
@@ -0,0 +1,17956 @@
+
+   [ [1]Contents ] [ [2]C-Kermit ] [ [3]Kermit Home ]
+
+                 Supplement to Using C-Kermit, Second Edition
+
+For C-Kermit 7.0
+
+As of C-Kermit version:  7.0.196
+This file last updated:  8 February 2000
+
+Authors: Frank da Cruz and Christine M. Gianone
+Address: The Kermit Project
+         Columbia University
+         612 West 115th Street
+         New York NY 10025-7799
+         USA
+Fax:     +1 (212) 662-6442
+E-Mail:  [4]kermit-support@columbia.edu
+Web:     [5]http://www.columbia.edu/kermit/
+Or:      [6]http://www.kermit-project.org/
+Or:      [7]http://www.columbia.nyc.ny.us/kermit/
+     _________________________________________________________________
+
+  NOTICES
+
+   This document:
+          Copyright © 1997, 2000, Frank da Cruz and Christine M. Gianone.
+          All rights reserved.
+
+   Kermit 95:
+          Copyright © 1995, 2000, Trustees of Columbia University in the
+          City of New York. All rights reserved.
+
+   C-Kermit:
+          Copyright © 1985, 2000,
+          Trustees of Columbia University in the City of New York. All
+          rights reserved. See the C-Kermit [8]COPYING.TXT file or the
+          copyright text in the [9]ckcmai.c module for disclaimer and
+          permissions.
+
+   When Kerberos(TM) and/or SRP(TM) (Secure Remote Password) and/or SSL
+          protocol are included:
+          Portions Copyright © 1990, Massachusetts Institute of
+          Technology.
+          Portions Copyright © 1991, 1993 Regents of the University of
+          California.
+          Portions Copyright © 1991, 1992, 1993, 1994, 1995 by AT&T.
+          Portions Copyright © 1997, Stanford University.
+          Portions Copyright © 1995-1997, Eric Young
+          <eay@cryptosoft.com>.
+
+   For the full text of the third-party copyright notices, see
+   [10]Appendix V.
+     _________________________________________________________________
+
+  WHAT IS IN THIS FILE
+
+   This file lists changes made to C-Kermit since the second edition of
+   the book [11]Using C-Kermit was published and C-Kermit 6.0 was
+   released in November 1996. Use this file as a supplement to the second
+   edition of Using C-Kermit until the third edition is published some
+   time in 2000. If the "most recent update" shown above is long ago,
+   contact Columbia University to see if there is a newer release.
+
+   For further information, also see the [12]CKCBWR.TXT ("C-Kermit
+   beware") file for hints, tips, tricks, restrictions, frequently asked
+   questions, etc, plus the system-specific "beware file", e.g.
+   [13]CKUBWR.TXT for UNIX, [14]CKVBWR.TXT for VMS, etc, and also any
+   system-specific update files such as KERMIT95.HTM for Kermit 95 (in
+   the DOCS\MANUAL\ subdirectory of your K95 directory).
+
+     This Web-based copy of the C-Kermit 7.0 update notes supersedes the
+     plain-text CKERMIT2.TXT file. All changes after 19 January 2000
+     appear only here in the Web version. If you need an up-to-date
+     plain-text copy, use your Web browser to save this page as plain
+     text. 
+     _________________________________________________________________
+
+  ABOUT FILENAMES
+
+   In this document, filenames are generally shown in uppercase, but on
+   file systems with case-sensitive names such as UNIX, OS-9, and AOS/VS,
+   lowercase names are used: [15]ckubwr.txt, [16]ckermit70.txt, etc.
+     _________________________________________________________________
+
+  ADDITIONAL FILES
+
+   Several other files accompany this new Kermit release:
+
+   SECURITY.TXT
+          Discussion of Kermit's new authentication and encryption
+          features:
+
+          + [17]Plain-text version
+          + [18]HTML (hypertext) version
+
+   IKSD.TXT
+          How to install and manage an Internet Kermit Service Daemon.
+
+          + [19]Plain-text version
+          + [20]HTML (hypertext) version
+
+          Also see [21]cuiksd.htm for instructions for use.
+
+   TELNET.TXT
+          A thorough presentation of Kermit's new advanced Telnet
+          features and controls.
+
+          + [22]Plain-text version
+          + [23]HTML (hypertext) version
+     _________________________________________________________________
+
+  THE NEW C-KERMIT LICENSE
+
+   The C-Kermit license was rewritten for version 7.0 to grant automatic
+   permission to packagers of free operating-system distributions to
+   include C-Kermit 7.0. Examples include Linux (GNU/Linux), FreeBSD,
+   NetBSD, etc. The new license is in the [24]COPYING.TXT file, and is
+   also displayed by C-Kermit itself when you give the VERSION or
+   COPYRIGHT command. The new C-Kermit license does not apply to
+   [25]Kermit 95.
+     _________________________________________________________________
+
+  ACKNOWLEDGMENTS
+
+   Thanks to Jeff Altman, who joined the Kermit Project in 1995, for much
+   of what you see in C-Kermit 7.0, especially in the networking and
+   security areas, and his key role in designing and implementing the
+   Internet Kermit Service Daemon. And special thanks to Lucas Hart for
+   lots of help with the VMS version; to Peter Eichhorn for continuous
+   testing on the full range of HP-UX versions and for a consolidated set
+   of HP-UX makefile targets; and to Colin Allen, Mark Allen, Roger
+   Allen, Ric Anderson, William Bader, Mitch Baker, Mitchell Bass, Nelson
+   Beebe, Gerry Belanger, Jeff Bernsten, Mark Berryman, John Bigg, Volker
+   Borchert, Jonathan Boswell, Tim Boyer, Frederick Bruckman, Kenneth
+   Cochran, Jared Crapo, Bill Delaney, Igor Sobrado Delgado, Clarence
+   Dold, Joe Doupnik, John Dunlap, Max Evarts, Patrick French, Carl
+   Friedberg, Carl Friend, Hirofumi Fujii, Andrew Gabriel, Gabe Garza,
+   Boyd Gerber, David Gerber, George Gilmer, Hunter Goatley, DJ Hagberg,
+   Kevin Handy, Andy Harper, Randolph Herber, Sven Holström, Michal
+   Jaegermann, Graham Jenkins, Dick Jones, Terry Kennedy, Robert D Keys,
+   Nick Kisseberth, Igor Kovalenko, David Lane, Adam Laurie, Jeff
+   Liebermann, Eric Lonvick, Hoi Wan Louis, Arthur Marsh, Gregorie
+   Martin, Peter Mauzey, Dragan Milicic, Todd Miller, Christian Mondrup,
+   Daniel Morato, Dat Nguyen, Herb Peyerl, Jean-Pierre Radley, Steve
+   Rance, Stephen Riehm, Nigel Roles, Larry Rosenman, Jay S Rouman, David
+   Sanderson, John Santos, Michael Schmitz, Steven Schultz, Bob Shair,
+   Richard Shuford, Fred Smith, Michael Sokolov, Jim Spath, Peter Szell,
+   Ted T'so, Brian Tillman, Linus Torvalds, Patrick Volkerding, Martin
+   Vorländer, Steve Walton, Ken Weaverling, John Weekley, Martin
+   Whitaker, Jim Whitby, Matt Willman, Joellen Windsor, Farrell Woods,
+   and many others for binaries, hosting, reviews, suggestions, advice,
+   bug reports, and all the rest over the 3+ year C-Kermit 7.0
+   development cycle. Thanks to Russ Nelson and the board of the Open
+   Software Initiative ([26]http://www.opensource.org) for their
+   cooperation in developing the new C-Kermit license and to the
+   proprietors of those free UNIX distributions that have incorporated
+   C-Kermit 7.0 for their cooperation and support, especially FreeBSD's
+   Jörg Wunsch.
+     _________________________________________________________________
+
+  NOTE TO KERMIT 95 USERS
+
+   Kermit 95 and C-Kermit share the same command and scripting language,
+   the same Kermit file-transfer protocol implementation, and much else
+   besides.
+
+   Like the book [27]Using C-Kermit, this file concentrates on the
+   aspects of C-Kermit that are common to all versions: UNIX, VMS,
+   Windows, OS/2, VOS, AOS/VS, etc. Please refer to your Kermit 95
+   documentation for information that is specific to Kermit 95.
+
+   C-Kermit 7.0 corresponds to Kermit 95 1.1.19.
+     _________________________________________________________________
+
+  C-KERMIT VERSIONS AND VERSION NUMBERS
+
+   "C-Kermit" refers to all the many programs that are compiled in whole
+   or in part from common C-language source code, comprising:
+
+     * A Kermit file transfer protocol module
+     * A command parser and script execution module
+     * A modem-dialing module
+     * A network support module
+     * A character-set translation module.
+
+   and several others. These "system-independent" modules are combined
+   with system-dependent modules for each platform to provide the
+   required input/output functions, and also in some cases overlaid with
+   an alternative user interface, such as Macintosh Kermit's
+   point-and-click interface, and in some cases also a terminal emulator,
+   as Kermit 95.
+
+   The C-Kermit version number started as 1.0, ... 3.0, 4.0, 4.1 and then
+   (because of confusion at the time with Berkeley UNIX 4.2), 4B, 4C, and
+   so on, with the specific edit number in parentheses, for example
+   4E(072) or 5A(188). This scheme was used through 5A(191), but now we
+   have gone back to the traditional numbering scheme with decimal
+   points: major.minor.edit; for example 7.0.196. Internal version
+   numbers (the \v(version) variable), however, are compatible in
+   C-Kermit 5A upwards.
+
+   Meanwhile, C-Kermit derivatives for some platforms (Windows,
+   Macintosh) might go through several releases while C-Kermit itself
+   remains the same. These versions have their own platform-specific
+   version numbers, such as Kermit 95 1.1.1, 1.1.2, and so on.
+
+   C-Kermit Version History:
+
+  1.0       1981-1982         Command-line only, 4.2 BSD UNIX only
+  2.0       (*)               (who remembers...)
+  3.0       May 1984          Command-line only, supports several platforms
+  4.0-4.1   Feb-Apr 1985 (*)  First interactive and modular version
+  4C(050)   May 1985
+  4D(060)   April 1986
+  4E(066)   August 1987       Long packets
+  4E(068)   January 1988
+  4E(072)   January 1989
+  4F(095)   August 1989 (*)   Attribute packets
+  5A(188)   November 1992     Scripting, TCP/IP, sliding windows (1)
+  5A(189)   September 1993    Control-char unprefixing
+  5A(190)   October 1994      Recovery
+  5A(191)   April 1995        OS/2 only
+  6.0.192   September 1996    Intelligent dialing, autodownload, lots more (2)
+  6.1.193   1997-98 (*)       Development only
+  6.1.194   June 1998         K95 only - switches, directory recursion, more
+  7.0.195   August 1999       IKSD + more (CU only as K95 1.1.18-CU)
+  7.0.196   1 January 2000    Unicode, lots more
+
+   (*) Never formally released (4.0 was a total rewrite)
+   (1) Using C-Kermit, 1st Edition
+   (2) Using C-Kermit, 2nd Edition
+     _________________________________________________________________
+
+CONTENTS
+
+ I.  [28]C-KERMIT DOCUMENTATION
+
+ II. [29]NEW FEATURES
+
+     (0) [30]INCOMPATIBILITIES WITH PREVIOUS RELEASES
+     (1) [31]PROGRAM AND FILE MANAGEMENT AND COMMANDS
+         1.0.  [32]Bug fixes
+         1.1.  [33]Command Continuation
+         1.2.  [34]Editor Interface
+         1.3.  [35]Web Browser and FTP Interface
+         1.4.  [36]Command Editing
+         1.5.  [37]Command Switches
+               1.5.1. [38]General Switch Syntax
+               1.5.2. [39]Order and Effect of Switches
+               1.5.3. [40]Distinguishing Switches from Other Fields
+               1.5.4. [41]Standard File Selection Switches
+               1.5.5. [42]Setting Preferences for Different Commands
+         1.6.  [43]Dates and Times
+         1.7.  [44]Partial Completion of Keywords
+         1.8.  [45]Command Recall
+         1.9.  [46]EXIT Messages
+         1.10. [47]Managing Keyboard Interruptions
+         1.11. [48]Taming the Wild Backslash -- Part Deux
+               1.11.1. [49]Background
+               1.11.2. [50]Kermit's Quoting Rules
+               1.11.3. [51]Passing DOS Filenames from Kermit to Shell Commands
+               1.11.4. [52]Using Variables to Hold DOS Filenames
+               1.11.5. [53]Passing DOS Filenames as Parameters to Macros
+               1.11.6. [54]Passing DOS File Names from Macro Parameters to the
+DOS Shell
+               1.11.7. [55]Passing DOS Filenames to Kermit from the Shell
+         1.12. [56]Debugging
+         1.13. [57]Logs
+         1.14. [58]Automatic File-Transfer Packet Recognition at the Command Pr
+ompt
+         1.15. [59]The TYPE Command
+         1.16. [60]The RESET Command
+         1.17. [61]The COPY and RENAME Commands
+         1.18. [62]The MANUAL Command
+         1.19. [63]String and Filename Matching Patterns
+         1.20. [64]Multiple Commands on One Line
+         1.21. [65]What Do I Have?
+         1.22. [66]Generalized File Input and Output
+               1.22.1. [67]Why Another I/O System?
+               1.22.2. [68]The FILE Command
+               1.22.3. [69]FILE Command Examples
+               1.22.4. [70]Channel Numbers
+               1.22.5. [71]FILE Command Error Codes
+               1.22.6. [72]File I/O Variables
+               1.22.7. [73]File I/O Functions
+               1.22.8. [74]File I/O Function Examples
+         1.23. [75]The EXEC Command
+         1.24. [76]Getting Keyword Lists with '?'
+     (2) [77]MAKING AND USING CONNECTIONS
+         2.0. [78]SET LINE and SET HOST Command Switches
+         2.1. [79]Dialing
+              2.1.1. [80]The Dial Result Message
+              2.1.2. [81]Long-Distance Dialing Changes
+              2.1.3. [82]Forcing Long-Distance Dialing
+              2.1.4. [83]Exchange-Specific Dialing Decisions
+              2.1.5. [84]Cautions about Cheapest-First Dialing
+              2.1.6. [85]Blind Dialing (Dialing with No Dialtone)
+              2.1.7. [86]Trimming the Dialing Dialog
+              2.1.8. [87]Controlling the Dialing Speed
+              2.1.9. [88]Pretesting Phone Number Conversions
+              2.1.10. [89]Greater Control over Partial Dialing
+              2.1.11. [90]New DIAL-related Variables and Functions
+              2.1.12. [91]Increased Flexibility of PBX Dialing
+              2.1.13. [92]The DIAL macro - Last-Minute Phone Number Conversions
+              2.1.14. [93]Automatic Tone/Pulse Dialing Selection
+              2.1.15. [94]Dial-Modifier Variables
+              2.1.16. [95]Giving Multiple Numbers to the DIAL Command
+         2.2. [96]Modems
+              2.2.1. [97]New Modem Types
+              2.2.2. [98]New Modem Controls
+         2.3. [99]TELNET and RLOGIN
+              2.3.0. [100]Bug Fixes
+              2.3.1. [101]Telnet Binary Mode Bug Adjustments
+              2.3.2. [102]VMS UCX Telnet Port Bug Adjustment
+              2.3.3. [103]Telnet New Environment Option
+              2.3.4. [104]Telnet Location Option
+              2.3.5. [105]Connecting to Raw TCP Sockets
+              2.3.6. [106]Incoming TCP Connections
+         2.4. [107]The EIGHTBIT Command
+         2.5. [108]The Services Directory
+         2.6. [109]Closing Connections
+         2.7. [110]Using C-Kermit with External Communication Programs
+              2.7.0. [111]C-Kermit over tn3270 and tn5250
+              2.7.1. [112]C-Kermit over Telnet
+              2.7.2. [113]C-Kermit over Rlogin
+              2.7.3. [114]C-Kermit over Serial Communication Programs
+              2.7.4. [115]C-Kermit over Secure Network Clients
+              2.7.4.1. [116]SSH
+              2.7.4.2. [117]SSL
+              2.7.4.3. [118]SRP
+              2.7.4.4. [119]SOCKS
+              2.7.4.5. [120]Kerberos and SRP
+         2.8. [121]Scripting Local Programs
+         2.9. [122]X.25 Networking
+              2.9.1. [123]IBM AIXLink/X.25 Network Provider Interface for AIX
+              2.9.2. [124]HP-UX X.25
+         2.10. [125]Additional Serial Port Controls
+         2.11. [126]Getting Access to the Dialout Device
+         2.12. [127]The Connection Log
+         2.13. [128]Automatic Connection-Specific Flow Control Selection
+         2.14. [129]Trapping Connection Establishment and Loss
+         2.15. [130]Contacting Web Servers with the HTTP Command
+     (3) [131]TERMINAL CONNECTION
+         3.1. [132]CONNECT Command Switches
+         3.2. [133]Triggers
+         3.3. [134]Transparent Printing
+         3.4. [135]Binary and Text Session Logs
+     (4) [136]FILE TRANSFER AND MANAGEMENT
+         4.0. [137]Bug Fixes, Minor Changes, and Clarifications
+         4.1. [138]File-Transfer Filename Templates
+         4.1.1. [139]Templates in the As-Name
+         4.1.2. [140]Templates on the Command Line
+         4.1.3. [141]Post-Transfer Renaming
+         4.2. [142]File-Transfer Pipes and Filters
+         4.2.1. [143]Introduction
+         4.2.1.1. [144]Terminology
+         4.2.1.2. [145]Notation
+         4.2.1.3. [146]Security
+         4.2.2. [147]Commands for Transferring from and to Pipes
+         4.2.2.1. [148]Sending from a Command
+         4.2.2.2. [149]Receiving to a Command
+         4.2.3. [150]Using File-Transfer Filters
+         4.2.3.1. [151]The SEND Filter
+         4.2.3.2. [152]The RECEIVE Filter
+         4.2.4. [153]Implicit Use of Pipes
+         4.2.5. [154]Success and Failure of Piped Commands
+         4.2.6. [155]Cautions about Using Pipes to Transfer Directory Trees
+         4.2.7. [156]Pipes and Encryption
+         4.2.8. [157]Commands and Functions Related to Pipes
+         4.2.8.1. [158]The OPEN !READ and OPEN !WRITE Commands
+         4.2.8.2. [159]The REDIRECT Command
+         4.2.8.3. [160]Receiving Mail and Print Jobs
+         4.2.8.4. [161]Pipe-Related Functions
+         4.3. [162]Automatic Per-File Text/Binary Mode Switching
+         4.3.1. [163]Exceptions
+         4.3.2. [164]Overview
+         4.3.3. [165]Commands
+         4.3.4. [166]Examples
+         4.4. [167]File Permissions
+         4.4.1. [168]When ATTRIBUTES PROTECTION is OFF
+         4.4.1.1. [169]Unix
+         4.4.1.2. [170]VMS
+         4.4.2. [171]When ATTRIBUTES PROTECTION is ON
+         4.4.2.1. [172]System-Specific Permissions
+         4.4.2.1.1. [173]UNIX
+         4.4.2.1.2. [174]VMS
+         4.4.2.2. [175]System-Independent Permissions
+         4.5. [176]File Management Commands
+         4.5.1. [177]The DIRECTORY Command
+         4.5.2. [178]The CD and BACK Commands
+         4.5.2.1. [179]Parsing Improvements
+         4.5.2.2. [180]The CDPATH
+         4.5.3. [181]Creating and Removing Directories
+         4.5.4. [182]The DELETE and PURGE Commands
+         4.6. [183]Starting the Remote Kermit Server Automatically
+         4.7. [184]File-Transfer Command Switches
+         4.7.1. [185]SEND Command Switches
+         4.7.2. [186]GET Command Switches
+         4.7.3. [187]RECEIVE Command Switches
+         4.8. [188]Minor Kermit Protocol Improvements
+         4.8.1. [189]Multiple Attribute Packets
+         4.8.2. [190]Very Short Packets
+         4.9. [191]Wildcard / File Group Expansion
+         4.9.1. [192]In UNIX C-Kermit
+         4.9.2. [193]In Kermit 95
+         4.9.3. [194]In VMS, AOS/VS, OS-9, VOS, etc.
+         4.10. [195]Additional Pathname Controls
+         4.11. [196]Recursive SEND and GET: Transferring Directory Trees
+         4.11.1. [197]Command-Line Options
+         4.11.2. [198]The SEND /RECURSIVE Command
+         4.11.3. [199]The GET /RECURSIVE Command
+         4.11.4. [200]New and Changed File Functions
+         4.11.5. [201]Moving Directory Trees Between Like Systems
+         4.11.6. [202]Moving Directory Trees Between Unlike Systems
+         4.12. [203]Where Did My File Go?
+         4.13. [204]File Output Buffer Control
+         4.14. [205]Improved Responsiveness
+         4.15. [206]Doubling and Ignoring Characters for Transparency
+         4.16. [207]New File-Transfer Display Formats
+         4.17. [208]New Transaction Log Formats
+         4.17.1. [209]The BRIEF Format
+         4.17.2. [210]The FTP Format
+         4.18. [211]Unprefixing NUL
+         4.19. [212]Clear-Channel Protocol
+         4.20. [213]Streaming Protocol
+         4.20.1. [214]Commands for Streaming
+         4.20.2. [215]Examples of Streaming
+         4.20.2.1. [216]Streaming on Socket-to-Socket Connections
+         4.20.2.2. [217]Streaming on Telnet Connections
+         4.20.2.3. [218]Streaming with Limited Packet Length
+         4.20.2.4. [219]Streaming on Dialup Connections
+         4.20.2.5. [220]Streaming on X.25 Connections
+         4.20.3. [221]Streaming - Preliminary Conclusions
+         4.21. [222]The TRANSMIT Command
+         4.22. [223]Coping with Faulty Kermit Implementations
+         4.22.1. [224]Failure to Accept Modern Negotiation Strings
+         4.22.2. [225]Failure to Negotiate 8th-bit Prefixing
+         4.22.3. [226]Corrupt Files
+         4.22.4. [227]Spurious Cancellations
+         4.22.5. [228]Spurious Refusals
+         4.22.6. [229]Failures during the Data Transfer Phase
+         4.22.7. [230]Fractured Filenames
+         4.22.8. [231]Bad File Dates
+         4.23. [232]File Transfer Recovery
+         4.24. [233]FILE COLLISION UPDATE Clarification
+         4.25. [234]Autodownload Improvements
+     (5) [235]CLIENT/SERVER
+         5.0. [236]Hints
+         5.1. [237]New Command-Line Options
+         5.2. [238]New Client Commands
+         5.3. [239]New Server Capabilities
+         5.3.1. [240]Creating and Removing Directories
+         5.3.2. [241]Directory Listings
+         5.4. [242]Syntax for Remote Filenames with Embedded Spaces
+         5.5. [243]Automatic Orientation Messages upon Directory Change
+         5.6. [244]New Server Controls
+         5.7. [245]Timeouts during REMOTE HOST Command Execution
+     (6) [246]INTERNATIONAL CHARACTER SETS
+         6.0. [247]ISO 8859-15 Latin Alphabet 9
+         6.1. [248]The HP-Roman8 Character Set
+         6.2. [249]Greek Character Sets
+         6.3. [250]Additional Latin-2 Character Sets
+         6.4. [251]Additional Cyrillic Character Sets
+         6.5. [252]Automatic Character-Set Switching
+         6.6. [253]Unicode
+         6.6.1. [254]Overview of Unicode
+         6.6.2. [255]UCS Byte Order
+         6.6.2. [256]UCS Transformation Formats
+         6.6.3. [257]Conformance Levels
+         6.6.4. [258]Relationship of Unicode with Kermit's Other Character Sets
+         6.6.5. [259]Kermit's Unicode Features
+         6.6.5.1. [260]File Transfer
+         6.6.5.2. [261]The TRANSLATE Command
+         6.6.5.3. [262]Terminal Connection
+         6.6.5.4. [263]The TRANSMIT Command
+         6.6.5.5. [264]Summary of Kermit Unicode Commands
+         6.7. [265]Client/Server Character-Set Switching
+     (7) [266]SCRIPT PROGRAMMING
+         7.0. [267]Bug Fixes
+         7.1. [268]The INPUT Command
+         7.1.1. [269]INPUT Timeouts
+         7.1.2. [270]New INPUT Controls
+         7.1.3. [271]INPUT with Pattern Matching
+         7.1.4. [272]The INPUT Match Result
+         7.2. [273]New or Improved Built-In Variables
+         7.3. [274]New or Improved Built-In Functions
+         7.4. [275]New IF Conditions
+         7.5. [276]Using More than Ten Macro Arguments
+         7.6. [277]Clarification of Function Call Syntax
+         7.7. [278]Autodownload during INPUT Command Execution
+         7.8. [279]Built-in Help for Functions.
+         7.9. [280]Variable Assignments
+         7.9.1. [281]Assignment Operators
+         7.9.2. [282]New Assignment Commands
+         7.10. [283]Arrays
+         7.10.1. [284]Array Initializers
+         7.10.2. [285]Turning a String into an Array of Words
+         7.10.3. [286]Arrays of Filenames
+         7.10.4. [287]Automatic Arrays
+         7.10.5. [288]Sorting Arrays
+         7.10.6. [289]Displaying Arrays
+         7.10.7. [290]Other Array Operations
+         7.10.8. [291]Hints for Using Arrays
+         7.10.9. [292]Do-It-Yourself Arrays
+         7.10.10. [293]Associative Arrays
+         7.11. [294]OUTPUT Command Improvements
+         7.12. [295]Function and Variable Diagnostics
+         7.13. [296]Return Value of Macros
+         7.14. [297]The ASSERT, FAIL, and SUCCEED Commands.
+         7.15. [298]Using Alarms
+         7.16. [299]Passing Arguments to Command Files
+         7.17. [300]Dialogs with Timed Responses
+         7.18. [301]Increased Flexibility of SWITCH Case Labels
+         7.19. "[302]Kerbang" Scripts
+         7.20. [303]IF and XIF Statement Syntax
+         7.20.1. [304]The IF/XIF Distinction
+         7.20.2. [305]Boolean Expressions (The IF/WHILE Condition)
+         7.21. [306]Screen Formatting and Cursor Control
+         7.22. [307]Evaluating Arithmetic Expressions
+         7.23. [308]Floating-Point Arithmetic
+         7.24. [309]Tracing Script Execution
+         7.25. [310]Compact Substring Notation
+         7.26. [311]New WAIT Command Options
+         7.26.1. [312]Waiting for Modem Signals
+         7.26.2. [313]Waiting for File Events
+         7.27. [314]Relaxed FOR and SWITCH Syntax
+     (8) [315]USING OTHER FILE TRANSFER PROTOCOLS
+     (9) [316]COMMAND-LINE OPTIONS
+         9.0. [317]Extended-Format Command-Line Options
+         9.1. [318]Command Line Personalities
+         9.2. [319]Built-in Help for Command Line Options
+         9.3. [320]New Command-Line Options
+    (10) [321]C-KERMIT AND G-KERMIT
+
+III. [322]APPENDICES
+
+III.1. [323]Character Set Tables
+III.1.1. [324]The Hewlett Packard Roman8 Character Set
+III.1.2. [325]Greek Character Sets
+III.1.2.1. [326]The ISO 8859-7 Latin / Greek Alphabet
+III.1.2.2. [327]The ELOT 927 Character Set
+III.1.2.3. [328]PC Code Page 869
+III.2. [329]Updated Country Codes
+
+IV. [330]ERRATA & CORRIGENDA: Corrections to "Using C-Kermit" 2nd Edition.
+V. [331]ADDITIONAL COPYRIGHT NOTICES
+     _________________________________________________________________
+
+I. C-KERMIT DOCUMENTATION
+
+   The user manual for C-Kermit is:
+
+     Frank da Cruz and Christine M. Gianone, [332]Using C-Kermit, Second
+     Edition, Digital Press / Butterworth-Heinemann, Woburn, MA, 1997,
+     622 pages, ISBN 1-55558-164-1.
+
+   [333]CLICK HERE for reviews.
+
+   The present document is a supplement to Using C-Kermit 2nd Ed, not a
+   replacement for it.
+
+   US single-copy price: $52.95; quantity discounts available. Available
+   in bookstores or directly from Columbia University:
+
+  The Kermit Project
+  Columbia University
+  612 West 115th Street
+  New York NY  10025-7799
+  USA
+  Telephone: +1 (212) 854-3703
+  Fax:       +1 (212) 662-6442
+
+   Domestic and overseas orders accepted. Price: US $44.95 (US, Canada,
+   and Mexico). Shipping: $4.00 within the USA; $15.00 to all other
+   countries. Orders may be paid by MasterCard or Visa, or prepaid by
+   check in US dollars. Add $65 bank fee for checks not drawn on a US
+   bank. Do not include sales tax. Inquire about quantity discounts.
+
+   You can also order by phone from the publisher, Digital Press /
+   [334]Butterworth-Heinemann, with MasterCard, Visa, or American
+   Express:
+
+  +1 800 366-2665   (Woburn, Massachusetts office for USA & Canada)
+  +44 1865 314627   (Oxford, England distribution centre for UK & Europe)
+  +61 03 9245 7111  (Melbourne, Vic, office for Australia & NZ)
+  +65 356-1968      (Singapore office for Asia)
+  +27 (31) 2683111  (Durban office for South Africa)
+
+   A [335]German-language edition of the First Edition is also available:
+
+     Frank da Cruz and Christine M. Gianone, C-Kermit - Einführung und
+     Referenz, Verlag Heinz Heise, Hannover, Germany (1994). ISBN
+     3-88229-023-4. Deutsch von Gisbert W. Selke. Price: DM 88,00.
+     Verlag Heinz Heise GmbH & Co. KG, Helstorfer Strasse 7, D-30625
+     Hannover. Tel. +49 (05 11) 53 52-0, Fax. +49 (05 11) 53 52-1 29.
+
+   The [336]Kermit file transfer protocol is specified in:
+
+     Frank da Cruz, Kermit, A File Transfer Protocol, Digital Press,
+     Bedford, MA, 1987, 379 pages, ISBN 0-932376-88-6. US single-copy
+     price: $39.95. Availability as above.
+
+   News and articles about Kermit software and protocol are published
+   periodically in the journal, [337]Kermit News. Subscriptions are free;
+   contact Columbia University at the address above.
+
+   Online news about Kermit is published in the
+   [338]comp.protocols.kermit.announce and
+   [339]comp.protocols.kermit.misc newsgroups.
+     _________________________________________________________________
+
+II. NEW FEATURES
+
+   Support for the Bell Labs Plan 9 operating system was added to version
+   6.0 too late to be mentioned in the book (although it does appear on
+   the cover).
+
+   Specific changes and additions are grouped together by major topic,
+   roughly corresponding to the chapters of [340]Using C-Kermit.
+     _________________________________________________________________
+
+  0. INCOMPATIBILITIES WITH PREVIOUS RELEASES
+
+    1. C-Kermit 7.0 uses FAST Kermit protocol settings by default. This
+       includes "unprefixing" of certain control characters. Because of
+       this, file transfers that worked with previous releases might not
+       work in the new release (but it is more likely that they will
+       work, and much faster). If a transfer fails, you'll get a
+       context-sensitive hint suggesting possible causes and cures.
+       Usually SET PREFIXING ALL does the trick.
+    2. C-Kermit 7.0 transfers files in BINARY mode by default. To restore
+       the previous behavior, put SET FILE TYPE TEXT in your C-Kermit
+       initialization file.
+    3. No matter whether FILE TYPE is BINARY or TEXT by default, C-Kermit
+       7.0 now switches between text and binary mode automatically on a
+       per-file basis according to various criteria, including (a) which
+       kind of platform is on the other end of the connection (if known),
+       (b) the version of Kermit on the other end, and (c) the file's
+       name (see [341]Section 4, especially [342]4.3). To disable this
+       automatic switching and restore the earlier behavior, put SET
+       TRANSFER MODE MANUAL in your C-Kermit initialization file. To
+       disable automatic switching for a particular transfer, include a
+       /TEXT or /BINARY switch with your SEND or GET command.
+    4. The RESEND and REGET commands automatically switch to binary mode;
+       previously if RESEND or REGET were attempted when FILE TYPE was
+       TEXT, these commands would fail immediately, with a message
+       telling you they work only when the FILE TYPE is BINARY. Now they
+       simply do this for you. See [343]Section 4.23 for additional
+       (important) information.
+    5. SET PREFIXING CAUTIOUS and MINIMAL now both prefix linefeed (10
+       and 138) in case rlogin, ssh, or cu are "in the middle", since
+       otherwise <LF>~ might appear in Kermit packets, and this would
+       cause rlogin, ssh, or cu to disconnect, suspend,escape back, or
+       otherwise wreck the file transfer. Xon and Xoff are now always
+       prefixed too, even when Xon/Xoff flow control is not in effect,
+       since unprefixing them has proven dangerous on TCP/IP connections.
+    6. In UNIX, VMS, Windows, and OS/2, the DIRECTORY command is built
+       into C-Kermit itself rather than implemented by running an
+       external command or program. The built-in command might not behave
+       the way the platform-specific external one did, but many options
+       are available for customization. Of course the underlying
+       platform-specific command can still be accessed with "!", "@", or
+       "RUN" wherever the installation does not forbid. In UNIX, the "ls"
+       command can be accessed directly as "ls" in C-Kermit. See
+       [344]Section 4.5.1 for details.
+    7. SEND ? prints a list of switches rather than a list of filenames.
+       If you want to see a list of filenames, use a (system-dependent)
+       construction such as SEND ./? (for UNIX, Windows, or OS/2), SEND
+       []? (VMS), etc. See [345]Sections 1.5 and [346]4.7.1.
+    8. In UNIX, OS-9, and Kermit 95, the wildcard characters in previous
+       versions were * and ?. In C-Kermit 7.0 they are *, ?, [, ], {, and
+       }, with dash used inside []'s to denote ranges and comma used
+       inside {} to separate list elements. If you need to include any of
+       these characters literally in a filename, precede each one with
+       backslash (\). See [347]Section 4.9.
+    9. SET QUIET { ON, OFF } is now on the command stack, just like SET
+       INPUT CASE, SET COUNT, SET MACRO ERROR, etc, as described on p.458
+       of [348]Using C-Kermit, 2nd Edition. This allows any macro or
+       command file to SET QUIET ON or OFF without worrying about saving
+       and restoring the global QUIET value. For example, this lets you
+       write a script that tries SET LINE on lots of devices until it
+       finds one free without spewing out loads of error messages, and
+       also without disturbing the global QUIET setting, whatever it was.
+   10. Because of the new "." operator (which introduces assignments),
+       macros whose names begin with "." can not be invoked "by name".
+       However, they still can be invoked with DO.
+   11. The syntax of the EVALUATE command has changed. See [349]Section
+       7.9.2. To restore the previous syntax, use SET EVALUATE OLD.
+   12. The \v(directory) variable now includes the trailing directory
+       separator; in previous releases it did not. This is to allow
+       constructions such as:
+  cd \v(dir)data.tmp
+       to work across platforms that might have different directory
+       notation, such as UNIX, Windows, and VMS.
+   13. Prior to C-Kermit 7.0, the FLOW-CONTROL setting was global and
+       sticky. In C-Kermit 7.0, there is an array of default flow-control
+       values for each kind of connection, that are applied automatically
+       at SET LINE/PORT/HOST time. Thus a SET FLOW command given before
+       SET LINE/PORT/HOST is likely to be undone. Therefore SET FLOW can
+       be guaranteed to have the desired effect only if given after the
+       SET LINE/PORT/HOST command.
+   14. Character-set translation works differently in the TRANSMIT
+       command when (a) the file character-set is not the same as the
+       local end of the terminal character-set, or (b) when the terminal
+       character-set is TRANSPARENT.
+     _________________________________________________________________
+
+  1. PROGRAM AND FILE MANAGEMENT AND COMMANDS
+
+  1.0. Bug Fixes
+
+   The following patches were issued to correct bugs in C-Kermit 6.0.
+   These are described in detail in the 6.0 PATCHES file. All of these
+   fixes have been incorporated in C-Kermit 6.1 (never released except as
+   K95 1.1.16-17) and 7.0.
+
+ 0001   All UNIX         C-Kermit mishandles timestamps on files before 1970
+ 0002   Solaris 2.5++    Compilation error on Solaris 2.5 with Pro C
+ 0003   All VMS          CKERMIT.INI Fix for VMS
+ 0004   VMS/VAX/UCX 2.0  C-Kermit 6.0 can't TELNET on VAX/VMS with UCX 2.0
+ 0005   All              C-Kermit Might Send Packets Outside Window
+ 0006   All              MOVE from SEND-LIST does not delete original files
+ 0007   Solaris 2.5++    Higher serial speeds on Solaris 2.5
+ 0008   All              C-Kermit application file name can't contain spaces
+ 0009   AT&T 7300 UNIXPC setuid and hardware flow-control problems
+ 0010   Linux on Alpha   Patch to make ckutio.c compile on Linux/Alpha
+ 0011   OS-9/68000 2.4   Patch to make ck9con.c compile on OS-9/68000 2.4
+ 0012   MW Coherent 4.2  Patches for successful build on Coherent 4.2
+ 0013   SINIX-Y 5.43     "delay" variable conflicts with <sys/clock.h>
+ 0014   VMS/VAX/CMU-IP   Subject: Patches for VAX/VMS 5.x + CMU-IP
+ 0015   All              XECHO doesn't flush its output
+ 0016   VMS              CD and other directory operations might not work
+ 0017   Linux 1.2.x++    Use standard POSIX interface for high serial speeds
+ 0018   UNIX             SET WILDCARD-EXPANSION SHELL dumps core
+ 0019   All              Hayes V.34 modem init string problem
+ 0020   All              READ command does not fail if file not open
+ 0021   All              Problems with long function arguments
+ 0022   All              Certain \function()s can misbehave
+ 0023   All              X MOD 0 crashes program
+ 0024   All              Internal bulletproofing for lower() function
+ 0025   OpenBSD          Real OpenBSD support for C-Kermit 6.0
+ 0026   All              Incorrect checks for macro/command-file nesting depth
+ 0027   All              ANSWER doesn't automatically CONNECT
+ 0028   All              Overzealous EXIT warning
+ 0029   All              OUTPUT doesn't echo when DUPLEX is HALF
+ 0030   All              Minor problems with REMOTE DIRECTORY/DELETE/etc
+ 0031   All              CHECK command broken
+ 0032   All              Problem with SET TRANSMIT ECHO
+ 0033   UNIX, VMS, etc   HELP SET SERVER says too much
+ 0034   All              READ and !READ too picky about line terminators
+ 0035   All              END from inside SWITCH doesn't work
+ 0036   All              Problem telnetting to multihomed hosts
+ 0037   All              Redirection failures in REMOTE xxx > file
+
+   REDIRECT was missing in many UNIX C-Kermit implementations; in version
+   7.0, it should be available in all of them.
+     _________________________________________________________________
+
+  1.1. Command Continuation
+
+   Comments that start with ";" or "#" can no longer be continued. In:
+
+  ; this is a comment -
+  echo blah
+
+   the ECHO command will execute, rather than being taken as a
+   continuation of the preceding comment line. This allows easy
+   "commenting out" of commands from macro definitions.
+
+   However, the text of the COMMENT command can still be continued onto
+   subsequent lines:
+
+  comment this is a comment -
+  echo blah
+
+   As of version 6.0, backslash is no longer a valid continuation
+   character. Only hyphen should be used for command continuation. This
+   is to make it possible to issue commands like "cd a:\" on DOS-like
+   systems.
+
+   As of version 7.0:
+
+     * You can quote a final dash to prevent it from being a continuation
+       character:
+  echo foo\-
+       This prints "foo-". The command is not continued.
+     * You can enter commands such as:
+  echo foo - ; this is a comment
+       interactively and they are properly treated as continued commands.
+       Previously this worked only in command files.
+     _________________________________________________________________
+
+  1.2. Editor Interface
+
+   SET EDITOR name [ options ]
+          Lets you specify a text-editing program. The name can be a
+          fully specified pathname like /usr/local/bin/emacs19/emacs, or
+          it can be the name of any program in your PATH, e.g. "set
+          editor emacs". In VMS, it must be a DCL command like "edit",
+          "edit/tpu", "emacs", etc. If an environment variable EDITOR is
+          defined when Kermit starts, its value is the default editor.
+          You can also specify options to be included on the editor
+          command line. Returns to Kermit when the editor exits.
+
+   EDIT [ filename ]
+          If the EDIT command is given without a filename, then if a
+          previous filename had been given to an EDIT command, it is
+          used; if not, the editor is started without a file. If a
+          filename is given, the editor is started on that file, and the
+          filename is remembered for subsequent EDIT commands.
+
+   SHOW EDITOR
+          Displays the full pathname of your text editor, if any, along
+          with any command line options, and the file most recently
+          edited (and therefore the default filename for your next EDIT
+          command).
+
+   Related variables: \v(editor), \v(editopts), \v(editfile).
+     _________________________________________________________________
+
+  1.3. Web Browser and FTP Interface
+
+   C-Kermit includes an FTP command, which simply runs the FTP program;
+   C-Kermit does not include any built-in support for Internet File
+   Transfer Protocol, nor any method for interacting directly with an FTP
+   server. In version 7.0, however, C-Kermit lets you specify your FTP
+   client:
+
+   SET FTP-CLIENT [ name [ options ] ]
+          The name is the name of the FTP executable. In UNIX, Windows,
+          or OS/2, it can be the filename of any executable program in
+          your PATH (e.g. "ftp.exe" in Windows, "ftp" in UNIX); elsewhere
+          (or if you do not have a PATH definition), it must be the fully
+          specified pathname of the FTP program. If the name contains any
+          spaces, enclose it braces. Include any options after the
+          filename; these depend the particular ftp client.
+
+   The Web browser interface is covered in the following subsections.
+     _________________________________________________________________
+
+    1.3.1. Invoking your Browser from C-Kermit
+
+   BROWSE [ url ]
+          Starts your preferred Web browser on the URL, if one is given,
+          otherwise on the most recently given URL, if any. Returns to
+          Kermit when the browser exits.
+
+   SET BROWSER [ name [ options ] ]
+          Use this command to specify the name of your Web browser
+          program, for example: "set browser lynx". The name must be in
+          your PATH, or else it must be a fully specified filename; in
+          VMS it must be a DCL command.
+
+   SHOW BROWSER
+          Displays the current browser, options, and most recent URL.
+
+   Related variables: \v(browser), \v(browsopts), \v(browsurl).
+
+   Also see [350]Section 2.15: Contacting Web Servers with the HTTP
+   Command.
+     _________________________________________________________________
+
+    1.3.2. Invoking C-Kermit from your Browser
+
+   The method for doing this depends, of course, on your browser. Here
+   are some examples:
+
+   Netscape on UNIX (X-based)
+          In the Options->Applications section, set your Telnet
+          application to:
+
+  xterm -e /usr/local/bin/kermit/kermit -J %h %p
+
+          (replace "/usr/local/bin/kermit/kermit" by C-Kermit's actual
+          pathname). -J is C-Kermit's command-line option to "be like
+          Telnet"; %h and %p are Netscape placeholders for hostname and
+          port.
+
+   Lynx on UNIX
+          As far as we know, this can be done only at compile time. Add
+          the following line to the Lynx userdefs.h file before building
+          the Lynx binary:
+
+  #define TELNET_COMMAND "/opt/bin/kermit -J"
+
+          And then add lines like the following to the Lynx.cfg file:
+
+  DOWNLOADER:Kermit binary download:/opt/bin/kermit -i -V -s %s -a %s:TRUE
+  DOWNLOADER:Kermit text download:/opt/bin/kermit -s %s -a %s:TRUE
+
+  UPLOADER:Kermit binary upload:/opt/bin/kermit -i -r -a %s:TRUE
+  UPLOADER:Kermit text upload:/opt/bin/kermit -r -a %s:TRUE
+  UPLOADER:Kermit text get:/opt/bin/kermit -g %s:TRUE
+  UPLOADER:Kermit binary get:/opt/bin/kermit -ig %s:TRUE
+
+   But none of the above is necessary if you make C-Kermit your default
+   Telnet client, which you can do by making a symlink called 'telnet' to
+   the C-Kermit 7.0 binary. See [351]Section 9.1 for details.
+     _________________________________________________________________
+
+  1.4. Command Editing
+
+   Ctrl-W ("Word delete") was changed in 7.0 to delete back to the
+   previous non-alphanumeric, rather than all the way back to the
+   previous space.
+     _________________________________________________________________
+
+  1.5. Command Switches
+
+   As of version 7.0, C-Kermit's command parser supports a new type of
+   field, called a "switch". This is an optional command modifier.
+
+    1.5.1. General Switch Syntax
+
+   A switch is a keyword beginning with a slash (/). If it takes a value,
+   then the value is appended to it (with no intervening spaces),
+   separated by a colon (:) or equal sign (=). Depending on the switch,
+   the value may be a number, a keyword, a filename, a date/time, etc.
+   Examples:
+
+  send oofa.txt                              ; No switches
+  send /binary oofa.zip                      ; A switch without a value
+  send /protocol:zmodem oofa.zip             ; A switch with a value (:)
+  send /protocol=zmodem oofa.zip             ; A switch with a value (=)
+  send /text /delete /as-name:x.x oofa.txt   ; Several switches
+
+   Like other command fields, switches are separated from other fields,
+   and from each other, by whitespace, as shown in the examples just
+   above. You can not put them together like so:
+
+  send/text/delete/as-name:x.x oofa.txt
+
+   (as you might do in VMS or DOS, or as we might once have done in
+   TOPS-10 or TOPS0-20, or PIP). This is primarily due to ambiguity
+   between "/" as switch introducer versus "/" as UNIX directory
+   separator; e.g. in:
+
+  send /delete/as-name:foo/text oofa.txt
+
+   Does "foo/text" mean the filename is "foo" and the transfer is to be
+   in text mode, or does it mean the filename is "foo/text"? Therefore we
+   require whitespace between switches to resolve the ambiguity. (That's
+   only one of several possible ambiguities -- it is also conceivable
+   that a file called "text" exists in the path "/delete/as-name:foo/").
+
+   In general, if a switch can take a value, but you omit it, then either
+   a reasonable default value is supplied, or an error message is
+   printed:
+
+  send /print:-Plaserwriter oofa.txt         ; Value included = print options
+  send /print oofa.txt                       ; Value omitted, OK
+  send /mail:kermit@columbia.edu oofa.txt    ; Value included = address
+  send /mail oofa.txt                        ; Not OK - address required
+  ?Address required
+
+   Context-sensitive help (?) and completion (Esc or Tab) are available
+   in the normal manner:
+
+  C-Kermit> send /pr? Switch, one of the following:
+    /print /protocol
+  C-Kermit> send /pro<ESC>tocol:?  File-transfer protocol,
+   one of the following:
+    kermit   xmodem   ymodem   ymodem-g   zmodem
+  C-Kermit> send /protocol:k<TAB>ermit
+
+   If a switch takes a value and you use completion on it, a colon (:) is
+   printed at the end of its name to indicate this. If it does not take a
+   value, a space is printed.
+
+   Also, if you type ? in a switch field, switches that take values are
+   shown with a trailing colon; those that don't take values are shown
+   without one.
+     _________________________________________________________________
+
+    1.5.2. Order and Effect of Switches
+
+   The order of switches should not matter, except that they are
+   evaluated from left to right, so if you give two switches with
+   opposite effects, the rightmost one is used:
+
+  send /text /binary oofa.zip                ; Sends oofa.zip in binary mode.
+
+   Like other command fields, switches have no effect whatsoever until
+   the command is entered (by pressing the Return or Enter key). Even
+   then, switches affect only the command with which they are included;
+   they do not have global effect or side effects.
+     _________________________________________________________________
+
+    1.5.3. Distinguishing Switches from Other Fields
+
+   All switches are optional. A command that uses switches lets you give
+   any number of them, including none at all. Example:
+
+  send /binary oofa.zip
+  send /bin /delete oofa.zip
+  send /bin /as-name:mupeen.zip oofa.zip
+  send oofa.zip
+
+   But how does Kermit know when the first "non-switch" is given? It has
+   been told to look for both a switch and for something else, the data
+   type of the next field (filename, number, etc). In most cases, this
+   works well. But conflicts are not impossible. Suppose, for example, in
+   UNIX there was a file named "text" in the top-level directory. The
+   command to send it would be:
+
+  send /text
+
+   But C-Kermit would think this was the "/text" switch. To resolve the
+   conflict, use braces:
+
+  send {/text}
+
+   or other circumlocutions such as "send //text", "send /./text", etc.
+
+   The opposite problem can occur if you give an illegal switch that
+   happens to match a directory name. For example:
+
+  send /f oofa.txt
+
+   There is no "/f" switch (there are several switches that begin with
+   "/f", so "/f" is ambiguous). Now suppose there is an "f" directory in
+   the root directory; then this command would be interpreted as:
+
+     Send all the files in the "/f" directory, giving each one an
+     as-name of "oofa.txt".
+
+   This could be a mistake, or it could be exactly what you intended;
+   C-Kermit has no way of telling the difference. To avoid situations
+   like this, spell switches out in full until you are comfortable enough
+   with them to know the minimum abbreviation for each one. Hint: use ?
+   and completion while typing switches to obtain the necessary feedback.
+     _________________________________________________________________
+
+    1.5.4. Standard File Selection Switches
+
+   The following switches are used on different file-oriented commands
+   (such as SEND, DIRECTORY, DELETE, PURGE) to refine the selection of
+   files that match the given specification.
+
+   /AFTER:date-time
+          Select only those files having a date-time later than the one
+          given. See [352]Section 1.6 for date-time formats. Synonym:
+          /SINCE.
+
+   /NOT-AFTER:date-time
+          Select only those files having a date-time not later than (i.e.
+          earlier or equal to) the one given. Synonym: /NOT-SINCE.
+
+   /BEFORE:date-time
+          Select only those files having a date-time earlier than the one
+          given.
+
+   /NOT-BEFORE:date-time
+          Select only those files having a date-time not earlier than
+          (i.e. later or equal to) the one given.
+
+   /DOTFILES
+          UNIX and OS-9 only: The filespec is allowed to match files
+          whose names start with (dot) period. Normally these files are
+          not shown.
+
+   /NODOTFILES
+          (UNIX and OS-9 only) Don't show files whose names start with
+          dot (period). This is the opposite of /DOTFILES, and is the
+          default. Note that when a directory name starts with a period,
+          the directory and (in recursive operations) all its
+          subdirectories are skipped.
+
+   /LARGER-THAN:number
+          Only select files larger than the given number of bytes.
+
+   /SMALLER-THAN:number
+          Only select files smaller than the given number of bytes.
+
+   /EXCEPT:pattern
+          Specifies that any files whose names match the pattern, which
+          can be a regular filename, or may contain "*" and/or "?"
+          metacharacters (wildcards), are not to be selected. Example:
+
+  send /except:*.log *.*
+
+          sends all files in the current directory except those with a
+          filetype of ".log". Another:
+
+  send /except:*.~*~ *.*
+
+          sends all files except the ones that look like Kermit or EMACS
+          backup files (such as "oofa.txt.~17~") (of course you can also
+          use the /NOBACKUP switch for this).
+
+          The pattern matcher is the same one used by IF MATCH string
+          pattern ([353]Section 7.4), so you can test your patterns using
+          IF MATCH. If you need to match a literal * or ? (etc), precede
+          it by a backslash (\). If the pattern contains any spaces, it
+          must be enclosed in braces:
+
+  send /except:{Foo bar} *.*
+
+          The pattern can also be a list of up to 8 patterns. In this
+          case, the entire pattern must be enclosed in braces, and each
+          sub-pattern must also be enclosed in braces; this eliminates
+          the need for designating a separator character, which is likely
+          to also be a legal filename character on some platform or
+          other, and therefore a source of confusion. You may include
+          spaces between the subpatterns but they are not necessary. The
+          following two commands are equivalent:
+
+  send /except:{{ck*.o} {ck*.c}} ck*.?
+  send /except:{{ck*.o}{ck*.c}} ck*.?
+
+          If a pattern is to include a literal brace character, precede
+          it with "\". Also note the apparent conflict of this list
+          format and the string-list format described in [354]Section
+          4.9.1. In case you want to include a wildcard string-list with
+          braces on its outer ends as an /EXCEPT: argument, do it like
+          this:
+
+  send /except:{{{ckuusr.c,ckuus2.c,ckuus6.c}}} ckuus*.c
+     _________________________________________________________________
+
+    1.5.5. Setting Preferences for Different Commands
+
+   Certain oft-used commands offer lots of switches because different
+   people have different requirements or preferences. For example, some
+   people want to be able to delete files without having to watch a list
+   of the deleted files scroll past, while others want to be prompted for
+   permission to delete each file. Different people prefer different
+   directory-listing styles. And so on. Such commands can be tailored
+   with the SET OPTIONS command:
+
+   SET OPTIONS command [ switch [ switch [ ... ] ] ]
+          Sets each switch as the default for the given command,
+          replacing the "factory default". Of course you can also
+          override any defaults established by the SET OPTIONS command by
+          including the relevant switches in the affected command any
+          time you issue it.
+
+   SHOW OPTIONS
+          Lists the commands that allows option-setting, and the options
+          currently in effect, if any, for each. Switches that have
+          synonyms are shown under their primary name; for example. /LOG
+          and /VERBOSE are shown as /LIST.
+
+   Commands for which options may be set include DIRECTORY, DELETE,
+   PURGE, and TYPE. Examples:
+
+  SET OPTIONS DIRECTORY /PAGE /NOBACKUP /HEADING /SORT:DATE /REVERSE
+  SET OPTIONS DELETE /LIST /NOHEADING /NOPAGE /NOASK /NODOTFILES
+  SET OPTIONS TYPE /PAGE
+
+   Not necessarily all of a command's switches can be set as options. For
+   example, file selection switches, since these would normally be
+   different for each command.
+
+   Put the desired SET OPTIONS commands in your C-Kermit customization
+   file for each command whose default switches you want to change every
+   time you run C-Kermit.
+     _________________________________________________________________
+
+  1.6. Dates and Times
+
+   Some commands and switches take date-time values, such as:
+
+  send /after:{8-Feb-2000 10:28:01}
+
+   Various date-time formats are acceptable. The rules for the date are:
+
+     * The year must have 4 digits.
+     * If the year comes first, the second field is the month.
+     * The day, month, and year may be separated by spaces, /, -, or
+       underscore.
+     * The month may be numeric (1 = January) or spelled out or
+       abbreviated in English.
+
+   If the date-time string contains any spaces, it must be enclosed in
+   braces. Examples of legal dates:
+
+                           Interpretation:
+  2000-Feb-8                8 February 2000
+  {2000 Feb 8}              8 February 2000
+  2000/Feb/8                8 February 2000
+  2000_Feb_8                8 February 2000
+  2000-2-8                  8 February 2000
+  2000-02-08                8 February 2000
+  8-Feb-2000                8 February 2000
+  08-Feb-2000               8 February 2000
+  12/25/2000                25 December 2000
+  25/12/2000                25 December 2000
+
+   The last two examples show that when the year comes last, and the
+   month is given numerically, the order of the day and month doesn't
+   matter as long as the day is 13 or greater (mm/dd/yyyy is commonly
+   used in the USA, whereas dd/mm/yyyy is the norm in Europe). However:
+
+  08/02/2000                Is ambiguous and therefore not accepted.
+
+   If a date is given, the time is optional and defaults to 00:00:00. If
+   the time is given with a date, it must follow the date, separated by
+   space, /, -, or underscore, and with hours, minutes, and seconds
+   separated by colon (:). Example:
+
+  2000-Feb-8 10:28:01       Represents 8 February 2000, 10:28:01am
+
+   If a date is not given, the current date is used and a time is
+   required.
+
+   Time format is hh:mm:ss or hh:mm or hh in 24-hour format, or followed
+   by "am" or "pm" (or "AM" or "PM") to indicate morning or afternoon.
+   Examples of times that are acceptable:
+
+                           Interpretation:
+  3:23:56                    3:23:56am
+  3:23:56am                  3:23:56am
+  3:23:56pm                  3:23:56pm = 15:23:56
+ 15:23:56                    3:23:56pm = 15:23:56
+  3:23pm                     3:23:00pm = 15:23:00
+  3:23PM                     3:23:00pm = 15:23:00
+  3pm                        3:00:00pm = 15:00:00
+
+   Examples of legal date-times:
+
+  send /after:{8 Feb 2000 10:28:01}
+  send /after:8_Feb_2000_10:28:01
+  send /after:8-Feb-2000/10:28:01
+  send /after:2000/02/08/10:28:01
+  send /after:2000/02/08_10:28:01
+  send /after:2000/02/08_10:28:01am
+  send /after:2000/02/08_10:28:01pm
+  send /after:2000/02/08_10:28pm
+  send /after:2000/02/08_10pm
+  send /after:10:00:00pm
+  send /after:10:00pm
+  send /after:10pm
+  send /after:22
+
+   Finally, there is a special all-numeric format you can use:
+
+  yyyymmdd hh:mm:ss
+
+   For example:
+
+  20000208 10:28:01
+
+   This is Kermit's standard date-time format (based on ISO 8601), and is
+   accepted (among other formats) by any command or switch that requires
+   a date-time, and is output by any function whose result is a calendar
+   date-time.
+
+   There are no optional parts to this format and it must be exactly 17
+   characters long, punctuated as shown (except you can substitute
+   underscore for space in contexts where a single "word" is required).
+   The time is in 24-hour format (23:00:00 is 11:00pm). This is the
+   format returned by \fdate(filename), so you can also use constructions
+   like this:
+
+  send /after:\fdate(oofa.txt)
+
+   which means "all files newer than oofa.txt".
+
+   Besides explicit dates, you can also use the any of the following
+   shortcuts:
+
+   TODAY
+          Stands for the current date at 00:00:00.
+
+   TODAY 12:34:56
+          Stands for the current date at the given time.
+
+   YESTERDAY
+          Stands for yesterday's date at 00:00:00. A time may also be
+          given.
+
+   TOMORROW
+          Stands for tomorrow's date at 00:00:00. A time may also be
+          given.
+
+   + number { DAYS, WEEKS, MONTHS, YEARS } [ time ]
+          Is replaced by the future date indicated, relative to the
+          current date. If the time is omitted, 00:00:00 is used.
+          Examples: +3days, +2weeks, +1year, +37months.
+
+   - number { DAYS, WEEKS, MONTHS, YEARS } [ time ]
+
+          Is replaced by the past date indicated, relative to the current
+          date. If the time is omitted, 00:00:00 is used.
+
+   The time can be separated from the date shortcut by any of the same
+   separators that are allowed for explicit date-times: space, hyphen,
+   slash, period, or underscore. In switches and other space-delimited
+   fields, use non-spaces to separate date/time fields, or enclose the
+   date-time in braces, e.g.:
+
+  purge /before:-4days_12:00:00
+  purge /before:{- 4 days 12:00:00}
+
+   Of course you can also use variables:
+
+  define \%n 43
+  purge /before:-\%ndays_12:00:00
+
+   Shortcut names can be abbreviated to any length that still
+   distinguishes them from any other name that can appear in the same
+   context, e.g. "TOD" for today, "Y" for yesterday. Also, the special
+   abbreviation "wks" is accepted for WEEKS, and "yrs" for "YEARS".
+
+   (To see how to specify dates relative to a specific date, rather than
+   the current one, see the [355]\fmjd() function description below.)
+
+   You can check date formats with the DATE command. DATE by itself
+   prints the current date and time in standard format: yyyymmdd
+   hh:mm:ss. DATE followed by a date and/or time (including shortcuts)
+   converts it to standard format if it can understand it, otherwise it
+   prints an error message.
+
+   The following variables and functions deal with dates and times; any
+   function argument designated as "date-time" can be in any of the
+   formats described above.
+
+   \v(day)
+          The first three letters of the English word for the current day
+          of the week, e.g. "Wed".
+
+   \fday(date-time)
+          The first three letters of the English word for day of the week
+          of the given date. If a time is included, it is ignored.
+          Example: \fday(8 Feb 1988) = "Mon".
+
+   \v(nday)
+          The numeric day of the week: 0 = Sunday, 1 = Monday, ..., 6 =
+          Saturday.
+
+   \fnday(date-time)
+          The numeric day of the week for the given date. If a time is
+          included, it is ignored. Example: \fnday(8 Feb 1988) = "1".
+
+   \v(date)
+          The current date as dd mmm yyyy, e.g. "08 Feb 2000" (as in this
+          example, a leading zero is supplied for day-of-month less than
+          10).
+
+   \v(ndate)
+          The current date in numeric format: yyyymmdd, e.g. "20000208".
+
+   \v(time)
+          The current time as hh:mm:ss, e.g. "15:27:14".
+
+   \ftime(time)
+          The given free-format date and/or time (e.g. "3pm") returns the
+          time (without the date) converted to hh:mm:ss 24-hour format,
+          e.g. "15:00:00" (the date, if given, is ignored).
+
+   \v(ntime)
+          The current time as seconds since midnight, e.g. "55634".
+
+   \v(tftime)
+          The elapsed time of the most recent file-transfer operation in
+          seconds.
+
+   \v(intime)
+          The elapsed time for the most recent INPUT command to complete,
+          in milliseconds.
+
+   \fntime(time)
+          The given free-format date and/or time is converted to seconds
+          since midnight (the date, if given, is ignored). This function
+          replaces \ftod2secs(), which is now a synonym for \fntime().
+          Unlike \ftod2secs(), \fntime() allows a date to be included,
+          and it allows the time to be in free format (like 3pm), and it
+          allows the amount of time to be more than 24 hours. E.g.
+          \fntime(48:00:00) = 172800. Example of use:
+
+  set alarm \fntime(48:00:00) ; set alarm 48 hours from now.
+
+   \fn2time(seconds)
+          The given number of seconds is converted to hh:mm:ss format.
+
+   \fdate(filename)
+          Returns the modification date-time of the given file in
+          standard format: yyyymmdd hh:mm:ss.
+
+   \fcvtdate(date-time)
+          Converts a free-format date and/or time to Kermit standard
+          format: yyyymmdd hh:mm:ss. If no argument is given, returns the
+          current date-time in standard format. If a date is given but no
+          time, the converted date is returned without a time. If a time
+          is given with no date, the current date is supplied. Examples:
+
+  \fcvtdate(4 Jul 2000 2:21:17pm) = 20000704 14:21:17
+  \fcvtdate() = 20000704 14:21:17 (on 4 Jul 2000 at 2:21:17pm).
+  \fcvtd(4 Jul 2000) = 20000704
+  \fcvtd(6pm) = 20000704 18:00:00 (on 4 Jul 2000 at 6:00pm).
+
+   \fdayofyear(date-time)
+   \fdoy(date-time)
+          Converts a free-format date and/or time to yyyyddd, where ddd
+          is the 3-digit day of the year, and 1 January is Day 1. If a
+          time is included with the date, it is returned in standard
+          format. If a date is included but no time, the date is returned
+          without a time. If a time is given with no date, the time is
+          converted and the current date is supplied. If no argument is
+          given, the current date-time is returned. Synonym: \fdoy().
+          Examples:
+
+  \fddayofyear(4 Jul 2000 2:21:17pm) = 2000185 14:21:17
+  \fdoy() = 2000185 14:21:17 (on 4 Jul 2000 at 2:21:17pm).
+  \fdoy(4 Jul 2000) = 2000185
+  \fdoy(6pm) = 2000185 18:00:00 (on 4 Jul 2000 at 6:00pm).
+
+   Note: The yyyyddd day-of-year format is often erroneously referred to
+   as a Julian date. However, a true Julian date is a simple counting
+   number, the number of days since a certain fixed day in the past.
+   [356]See \fmjd() below.
+
+   \fdoy2date(date-time)
+          Converts a date or date-time in day-of-year format to a
+          standard format date. A yyyyddd-format date must be supplied;
+          time is optional. The given date is converted to yyyymmdd
+          format. If a time is given, it is converted to 24-hour format.
+          Examples:
+
+  \fdoy2date(2000185) = 20000704
+  \fdoy2(2000185 3pm) = 20000704 15:00:00
+
+   \fmjd(date-time)
+          Converts free-format date and/or time to a Modified Julian Date
+          (MJD), the number of days since 17 Nov 1858 00:00:00. If a time
+          is given, it is ignored. Examples:
+
+  \fmjd(4 Jul 2000) = 50998
+  \fmjd(17 Nov 1858) = 0
+  \fmjd(16 Nov 1858) = -1
+
+   \fmjd2date(mjd)
+          Converts an MJD (integer) to standard date format, yyyymmdd:
+
+  \fmjd2(50998) = 4 Jul 1998
+  \fmjd2(0) = 17 Nov 1858
+  \fmjd2(-1) = 16 Nov 1858
+  \fmjd2(-365) = 17 Nov 1857
+
+   MJDs are normal integers and, unlike DOYs, may be added, subtracted,
+   etc, with each other or with other integers, to obtain meaningful
+   results. For example, to find out the date 212 days ago:
+
+  echo \fmjd2date(\fmjd()-212)
+
+   Constructions such as this can be used in any command where a
+   date-time is required, e.g.:
+
+  send /after:\fmjd2date(\fmjd()-212)
+
+   to send all files that are not older than 212 days (this is equivalent
+   to "send /after:-212days").
+
+   MJDs also have other regularities not exhibited by other date formats.
+   For example, \fmodulus(\fmjd(any-date),7) gives the day of the week
+   for any date (where 4=Sun, 5=Mon, ..., 3=Sat). (However, it is easier
+   to use \fnday() for this purpose, and it gives the more conventional
+   result of 0=Sun, 1=Mon, ..., 6=Sat).
+
+   Note that if MJDs are to be compared, they must be compared
+   numerically (IF <, =, >) and not lexically (IF LLT, EQUAL, LGT),
+   whereas DOYs must be compared lexically if they include a time (which
+   contains ":" characters); however, if DOYs do not include a time, they
+   may also be compared numerically.
+
+   In any case, lexical comparison of DOYs always produces the
+   appropriate result, as does numeric comparison of MJDs.
+
+   The same comments apply to sorting. Also note that DOYs are fixed
+   length, but MJDs can vary in length. However, all MJDs between 3 April
+   1886 and 30 Aug 2132 are 5 decimal digits long. (MJDs become 6 digits
+   long on 31 Aug 2132, and 7 digits long on 13 Oct 4596).
+     _________________________________________________________________
+
+  1.7. Partial Completion of Keywords
+
+   Partial completion of keywords was added in C-Kermit 7.0. In prior
+   versions, if completion was attempted (by pressing the Esc or Tab key)
+   on a string that matched different keywords, you'd just get a beep.
+   Now Kermit completes up to the first character where the possibly
+   matching keywords differ and then beeps. For example:
+
+  C-Kermit> send /n<Tab>
+
+   which matches /NOT-BEFORE and /NOT-AFTER, now completes up to the
+   dash:
+
+  C-Kermit> send /n<Tab>ot-<Beep>
+
+   Partial completion works for filenames too (as it has for some years).
+     _________________________________________________________________
+
+  1.8. Command Recall
+
+   C-Kermit has had a command history buffer for some time, which could
+   be scrolled interactively using control characters or (in Kermit 95
+   only) arrow keys. Version 7.0 adds a REDO command that allows the most
+   recent command matching a given pattern to be re-executed:
+
+   { REDO, RR, ^ } [ pattern ]
+          Search the command history list for the most recent command
+          that matches the given pattern, and if one is found, execute it
+          again.
+
+   The pattern can be a simple string (like "send"), in which case the
+   last SEND command is re-executed. Or it can contain wildcard
+   characters "*" and/or "?", which match any string and any single
+   character, respectively (note that "?" must be preceded by backslash
+   to override its normal function of giving help), and in most C-Kermit
+   versions may also include [] character lists and {} string lists (see
+   [357]Section 4.9).
+
+   The match works by appending "*" to the end of the given pattern (if
+   you didn't put one there yourself). Thus "redo *oofa" becomes "redo
+   *oofa*" and therefore matches the most recent command that contains
+   "oofa" anywhere within the command. If you want to inhibit the
+   application of the trailing "*", e.g. to force matching a string at
+   the end of a command, enclose the pattern in braces:
+
+  redo {*oofa}
+
+   matches the most recent command that ends with "oofa".
+
+   REDO commands themselves are not entered into the command history
+   list. If no pattern is given, the previous (non-REDO) command is
+   re-executed. The REDOne command is reinserted at the end of the
+   command history buffer, so the command scrollback character (Ctrl-P,
+   Ctrl-B, or Uparrow) can retrieve it.
+
+   Examples:
+
+  C-Kermit> echo foo
+  foo
+  C-Kermit> show alarm
+  (no alarm set)
+  C-Kermit> echo blah
+  blah
+  C-Kermit> redo          ; Most recent command
+  blah
+  C-Kermit> redo s        ; Most recent command starting with "s"
+  (no alarm set)
+  C-Kermit> redo echo f   ; Most recent command starting with "echo f"
+  foo
+  C-Kermit> redo *foo     ; Most recent command that has "foo" in it
+  foo
+  C-Kermit> <Ctrl-P>      ; Scroll back
+  C-Kermit> echo foo      ; The REDOne command is there
+  C-Kermit> redo {*foo}   ; Most recent command that ends with "foo"
+  foo
+  C-Kermit>
+
+   Since REDO, REDIAL, and REDIRECT all start the same way, and RED is
+   the designated non-unique abbreviation for REDIAL, REDO must be
+   spelled out in full. For convenience, RR is included as an invisible
+   easy-to-type synonym for REDO. You can also use the "^" character for
+   this:
+
+  C-Kermit> ^             ; Most recent command
+  C-Kermit> ^ s           ; Most recent command starting with "s"
+  C-Kermit> ^s            ; Ditto (space not required after "^").
+  C-Kermit> ^*foo         ; Most recent command that has "foo" in it.
+  C-Kermit> ^{*foo}       ; Most recent command ends with "foo".
+
+   Unlike the manual command-history-scrolling keys, the REDO command can
+   be used in a script, but it's not recommended (since the command to be
+   REDOne might not be found, so if the REDO command fails, you can't
+   tell whether it was because REDO failed to find the requested command,
+   or because the command was found but it failed).
+     _________________________________________________________________
+
+  1.9. EXIT Messages
+
+   The EXIT and QUIT commands now accept an optional message to be
+   printed. This makes the syntax of EXIT and QUIT just like END and
+   STOP:
+
+   { EXIT, QUIT, END, STOP } [ status-code [ message ] ]
+
+   where status-code is a number (0 indicating success, nonzero
+   indicating failure). This is handy in scripts that are never supposed
+   to enter interactive mode:
+
+  dial 7654321
+  if fail exit 1 Can't make connection - try again later.
+
+   Previously this could only be done in two steps:
+
+  dial 7654321
+  xif fail { echo Can't make connection - try again later, exit 1 }
+
+   A status code must be included in order to specify a message. In the
+   case of EXIT and QUIT, the default status code is contained in the
+   variable \v(exitstatus), and is set automatically by various events
+   (file transfer failures, etc; it can also be set explicitly with the
+   SET EXIT STATUS command). If you want to give an EXIT or QUIT command
+   with a message, but without changing the exit status from what it
+   normally would have been, use the \v(exitstatus) variable, e.g.:
+
+   exit \v(existatus) Goodbye from \v(cmdfile).
+
+   The EXIT status is returned to the system shell or whatever other
+   process invoked C-Kermit, e.g. in UNIX:
+
+  C-Kermit> exit 97 bye bye
+  bye bye
+  $ echo $?
+  97
+  $
+     _________________________________________________________________
+
+  1.10. Managing Keyboard Interruptions
+
+   When C-Kermit is in command or file-transfer mode (as opposed to
+   CONNECT mode), it can be interrupted with Ctrl-C. Version 7.0 adds the
+   ability to disarm the Ctrl-C interrupt:
+
+   SET COMMAND INTERRUPT { ON, OFF }
+          COMMAND INTERRUPT is ON by default, meaning the Ctrl-C can be
+          used to interrupt a command or a file transfer in progress. Use
+          OFF to disable these interruptions, and use it with great
+          caution for obvious reasons.
+
+   SET TRANSFER INTERRUPT { ON, OFF }
+          This can be used to disable keyboard interruption of file
+          transfer when C-Kermit is in local mode, or to re-enable it
+          after it has been disabled. This applies to the X, Z, E, and
+          similar keys as well as to the system interrupt character,
+          usually Ctrl-C. This is distinct from SET TRANSFER
+          CANCELLATION, which tells whether packet mode can be exited by
+          sending a special sequence of characters.
+
+   Several other commands can be interrupted by pressing any key while
+   they are active. Version 7.0 adds the ability to disable this form of
+   interruption also:
+
+   SET INPUT CANCELLATION { ON, OFF }
+          Whether an INPUT command in progress can be interrupted by
+          pressing a key. Normally ON. Setting INPUT CANCELLATION OFF
+          makes INPUT commands uninterruptible except by Ctrl-C (unless
+          COMMAND INTERRUPTION is also OFF).
+
+   SET SLEEP CANCELLATION { ON, OFF }
+          Whether a SLEEP, PAUSE, or WAIT command in progress can be
+          interrupted by pressing a key. Normally ON. Setting SLEEP
+          CANCELLATION OFF makes these commands uninterruptible except by
+          Ctrl-C (unless COMMAND INTERRUPTION is also OFF). Synonyms: SET
+          PAUSE CANCELLATION, SET WAIT CANCELLATION.
+
+   So to make certain a script is not interruptible by the user, include
+   these commands:
+
+  SET TRANSFER INTERRUPT OFF
+  SET SLEEP CANCELLATION OFF
+  SET INPUT CANCELLATION OFF
+  SET COMMAND INTERRUPTION OFF
+
+   Make sure to turn them back on afterwards if interruption is to be
+   re-enabled.
+
+   When a PAUSE, SLEEP, WAIT, or INPUT command is interrupted from the
+   keyboard, the new variable \v(kbchar) contains a copy of the (first)
+   character that was typed and caused the interruption, provided it was
+   not the command interrupt character (usually Ctrl-C). If these
+   commands complete successfully or time out without a keyboard
+   interruption, the \v(kbchar) variable is empty.
+
+   The \v(kbchar) variable (like any other variable) can be tested with:
+
+  if defined \v(kbchar) command
+
+   The command is executed if the variable is not empty.
+
+   The \v(kbchar) variable can be reset with WAIT 0 (PAUSE 0, SLEEP 0,
+   etc).
+     _________________________________________________________________
+
+  1.11. Taming The Wild Backslash -- Part Deux
+
+   [358]Using C-Kermit, 2nd Edition, contains a brief section, "Taming
+   the Wild Backslash", on page 48, which subsequent experience has shown
+   to be inadequate for Kermit users intent on writing scripts that deal
+   with Windows, DOS, and OS/2 filenames, in which backslash (\) is used
+   as the directory separator. This section fills in the blanks.
+
+    1.11.1. Background
+
+   The Kermit command language shares a certain unavoidable but annoying
+   characteristic with most other command languages that are capable of
+   string replacement, namely the necessity to "quote" certain characters
+   when you want them to be taken literally. This is a consequence of the
+   facts that:
+
+    1. One or more characters must be set aside to denote replacement,
+       rather than acting as literal text.
+    2. We have only 96 printable characters to work with in ASCII, which
+       is still the only universally portable character set.
+    3. There is no single printable character that is unused everywhere.
+    4. Variables are not restricted to certain contexts, as they are in
+       formal programming languages like C and Fortran, but can appear
+       anywhere at all within a command, and therefore require special
+       syntax.
+
+   Thus there can be conflicts. To illustrate, the standard UNIX shell
+   uses dollar sign ($) to introduce variables. So the shell command:
+
+  echo $TERM
+
+   displays the value of the TERM variable, e.g. vt320. But suppose you
+   want to display a real dollar sign:
+
+  echo The price is $10.20
+
+   This causes the shell to evaluate the variable "$1", which might or
+   might not exist, and substitute its value, e.g.:
+
+  The price is 0.20
+
+   (in this case the $1 variable had no value.) This is probably not what
+   you wanted. To force the dollar sign to be taken literally, you must
+   apply a "quoting rule", such as "precede a character by backslash (\)
+   to force the shell to take the character literally":
+
+  echo The price is \$10.20
+  The price is $10.20
+
+   But now suppose you want the backslash AND the dollar sign to be taken
+   literally:
+
+  echo The price is \\$10.20
+
+   This doesn't work, since the first backslash quotes the second one,
+   thereby leaving the dollar sign unquoted again:
+
+  The price is \0.20
+
+   Quoting the dollar sign requires addition of a third backslash:
+
+  echo The price is \\\$10.20
+  The price is \$10.20
+
+   The first backslash quotes the second one, and the third backslash
+   quotes the dollar sign.
+
+   Every command language -- all UNIX shells, VMS DCL, DOS Batch, AOS/VS
+   CLI, etc etc -- has similar rules. UNIX shell rules are probably the
+   most complicated, since many printable characters -- not just one --
+   are special there: dollar sign, single quote, double quote, backslash,
+   asterisk, accent grave, number sign, ampersand, question mark,
+   parentheses, brackets, braces, etc -- practically every
+   non-alphanumeric character needs some form of quoting if it is to be
+   taken literally. And to add to the confusion, the UNIX shell offers
+   many forms of quoting, and many alternative UNIX shells are available,
+   each using slightly different syntax.
+     _________________________________________________________________
+
+    1.11.2. Kermit's Quoting Rules
+
+   Kermit's basic quoting rules are simple by comparison (there are, of
+   course, additional syntax requirements for macro definitions, command
+   blocks, function calls, etc, but they are not relevant here).
+
+   The following characters are special in Kermit commands:
+
+   Backslash (\)
+          Introduces a variable, or the numeric representation of a
+          special character, or a function, or other item for
+          substitution. If the backslash is followed by a digit or by any
+          of the following characters:
+
+  x, o, d, m, s, f, v, $, %, &, :, {
+
+          this indicates a special substitution item; otherwise the
+          following character is to be taken literally (exceptions: \ at
+          end of line is taken literally; \n, \b, and \n are special
+          items in the OUTPUT command only).
+
+   Semicolon (;)
+          (Only when at the beginning of a line or preceded by at least
+          one space or tab) Introduces a comment.
+
+   Number sign (#)
+          (Only when at the beginning of a line or preceded by at least
+          one space or tab) Just like semicolon; introduces a comment.
+
+   Question mark (?)
+          (Only at the command prompt - not in command files or macros)
+          Requests context-sensitive help.
+
+   To force Kermit to take any of these characters literally, simply
+   precede it by a backslash (\).
+
+   Sounds easy! And it is, except when backslash also has a special
+   meaning to the underlying operating system, as it does in DOS,
+   Windows, and OS/2, where it serves as the directory separator in
+   filenames such as:
+
+  D:\K95\KEYMAPS\READ.ME
+
+   Using our rule, we would need to refer to this file in Kermit commands
+   as follows:
+
+  D:\\K95\\KEYMAPS\\READ.ME
+
+   But this would not be obvious to new users of Kermit software on DOS,
+   Windows, or OS/2, and it would be annoying to seasoned ones. Thus
+   MS-DOS Kermit and Kermit 95 go to rather extreme lengths to allow the
+   more natural notation, as in:
+
+  send d:\k95\keymaps\read.me
+
+   The reason this is tricky is that we also need to allow for variables
+   and other expressions introduced by backslash in the same command. For
+   example, suppose \%a is a variable whose value is "oofa" (without the
+   quotes). What does the following command do?
+
+  send d:\%a
+
+   Does it send the file named "oofa" in the current directory of the D:
+   disk, or does it send a file named "%a" in the root directory of the
+   D: disk? This is the kind of trouble we get into when we attempt to
+   bend the rules in the interest of user friendliness. (The answer is:
+   if the variable \%a has definition that is the name of an existing
+   file, that file is sent; if a file d:\%a exists, it is sent; otherwise
+   if both conditions are true, the variable takes precedence, and the
+   literal filename can be forced by quoting: \\%a.)
+
+   In Kermit 95 (but not MS-DOS Kermit), we also bend the rules another
+   way by allowing you to use forward slash (/) rather than backslash (\)
+   as the directory separator:
+
+  send d:/k95/keymaps/read.me
+
+   This looks more natural to UNIX users, and in fact is perfectly
+   acceptable to the Windows 95/98/NT and OS/2 operating systems on the
+   API level. BUT (there is always a "but") the Microsoft shell,
+   COMMAND.COM, for Windows 95/98 and NT does not allow this notation,
+   and therefore it can not be used in any Kermit command -- such as RUN
+   -- that invokes the Windows command shell AND your command shell is
+   COMMAND.COM or any other shell that does not allow forward slash as
+   directory separator (some alternative shells do allow this).
+
+     NOTE: There exists a wide variety of alternative shells from third
+     parties that do not have this restriction. If you are using a shell
+     that accepts forward slash as a directory separator, you can stop
+     reading right now -- UNLESS (there is always an "unless") you want
+     your scripts to be portable to systems that have other shells. Also
+     note that some Windows shells might actually REQUIRE forward
+     slashes (instead of backslashes) as directory separators; we do not
+     treat this situation below, but the treatment is obvious -- use
+     slash rather backslash as the directory separator.
+     _________________________________________________________________
+
+    1.11.3. Passing DOS Filenames from Kermit to Shell Commands
+
+   The following Kermit commands invoke the system command shell:
+
+  RUN (and its synonyms ! and @)
+  REDIRECT
+  PIPE
+
+   Each of these commands takes a shell command as an operand. These
+   shell commands are not, and can not be, parsed by Kermit since Kermit
+   does not know the syntax of shell commands, and so can't tell the
+   difference between a keyword, a filename, a variable, a switch, or
+   other item. Therefore the rules can not be bent since Kermit doesn't
+   know where or how to bend them. To illustrate (using the regular
+   Windows shell):
+
+  run c:\\windows\\command\\chkdsk.exe
+
+   works OK, but:
+
+  run c:/windows/command/chkdsk.exe
+
+   is not accepted by COMMAND.COM. But:
+
+  run c:\windows\command\chkdsk.exe
+
+   results in Kermit applying its quoting rules before sending the text
+   to the shell. Since "w" and "c" are not in the list of backslash-item
+   codes, the backslash means "take the following character literally".
+   Thus, by the time this filename gets to the Windows shell, it has
+   become:
+
+  c:windowscommandchkdsk.exe
+
+   which is probably not what you wanted. (If "w" and "c" were in the
+   list, the results could be even stranger.) Even more confusing is the
+   case where a directory or filename starts with one or more digits:
+
+  run c:\123\lotus.exe
+
+   in which "\123" is the Kermit notation for ASCII character 123, which
+   happens to be left brace ({), resulting in "c:{lotus.exe".
+
+   So when passing filenames to a Windows shell, always use double
+   backslashes as directory separators, to ensure that the shell gets
+   single backslashes:
+
+  run c:\\windows\\command\\chkdsk.exe
+  run c:\\123\\lotus.exe
+
+   Similar problems might occur with the built-in EDIT, BROWSE, and FTP
+   commands. These commands result in Kermit building a shell command
+   internally to invoke the associated helper program; the form of this
+   command might conflict with the form demanded by certain alternative
+   shells.
+     _________________________________________________________________
+
+    1.11.4. Using Variables to Hold DOS Filenames
+
+   Now to the next level. Suppose you want to write a script in which
+   filenames are parameters, and therefore are stored in variables.
+   Example:
+
+  define \%f c:\windows\command\chkdsk.exe
+  ...
+  run \%f
+
+   Obviously this won't work for the reasons just noted; the RUN command
+   requires directory separators be coded as double backslashes:
+
+  define \%f c:\\windows\\command\\chkdsk.exe
+  ...
+  run \%f
+
+   This will work; no surprises here. However, if you had used ASSIGN
+   rather than DEFINE, you might have been surprised after all; review
+   pages 348-349 of [359]Using C-Kermit (2nd Ed) for the difference
+   between DEFINE and ASSIGN.
+
+   We have said that any Kermit 95 or MS-DOS Kermit command that parses
+   filenames itself -- SEND, for example -- does not require double
+   backslashes since it knows it is parsing a filename. So since the
+   following works:
+
+  send c:\windows\command\chkdsk.exe
+
+   Should the following also work?
+
+  define \%f c:\windows\command\chkdsk.exe
+  ...
+  send \%f
+
+   Answer: No. Why? Because \%f is evaluated "recursively", to allow for
+   the possibility that its definition contains further variable
+   references. This is true of all "backslash-percent-letter" (or -digit)
+   variables, and also for array references. So \%f becomes
+   c:\windows\command\chkdsk.exe, which becomes
+   c:windowscommandchkdsk.exe.
+
+   The trick here is to use the "other" kind of variable, that is
+   evaluated only "one level deep" rather than recursively:
+
+  define filename c:\windows\command\chkdsk.exe
+  ...
+  send \m(filename)
+
+   Similarly if you want to prompt the user for a filename:
+
+  ask filename { Please type a filename: }
+   Please type a filename: c:\windows\command\chkdsk.exe
+  send \m(filename)
+     _________________________________________________________________
+
+    1.11.5. Passing DOS Filenames as Parameters to Macros
+
+   Suppose you want to pass a DOS filename containing backslashes as a
+   parameter to a Kermit macro. This raises two issues:
+
+    1. Parameters to macros are "just text" and so are fully evaluated
+       before they are passed to the macro.
+    2. Once inside the macro, the formal parameters \%1, \%2, ... \%9 are
+       the type of variable that is evaluated recursively.
+
+   Thus a DOS filename is ruined once in the act of parsing the macro
+   invocation, and again when referring to it from within the macro. To
+   illustrate, suppose "test" is a macro. Then in the invocation:
+
+  test c:\mydir\blah.txt
+
+   "c:mydirblah.txt" is assigned to \%1. However, if we double the
+   backslashes:
+
+  test c:\\mydir\\blah.txt
+
+   "c:\mydir\blah.txt" is assigned to \%1. But then when you refer to \%1
+   in the macro, it is evaluated recursively, resulting in
+   "c:mydirblah.txt". To illustrate:
+
+  define test echo \%1
+  test c:\mydir\blah.txt
+  c:mydirblah.txt
+  test c:\\mydir\\blah.txt
+  c:mydirblah.txt
+  test c:\\\\mydir\\\\blah.txt
+  c:\mydir\blah.txt
+
+   Let's address each part of the problem separately. First, inside the
+   macro. You can use the \fcontents() function to force a
+   backslash-percent variable (such as a macro argument) to be evaluated
+   one level deep instead of recursively, for example:
+
+  define test echo { The filename is "\fcontents(\%1)"}
+
+  test c:\mydir\blah.txt               ; We don't expect this to work
+   The filename is "c:mydirblah.txt"   ; and it doesn't.
+  test c:\\mydir\\blah.txt             ; But this does...
+   The filename is "c:\mydir\blah.txt"
+
+   Thus if the filename arrives inside the macro with single backslashes,
+   the backslashes are preserved if you always refer to the parameter
+   through the \fcontents() function.
+
+   Now how to ensure that backslashes are not stripped or misinterpreted
+   when passing a filename to a macro? This brings us back to what we
+   learned in earlier sections:
+
+    1. If it is a literal filename, either double the backslashes, or (if
+       the filename is to be used only within Kermit itself and not
+       passed to a DOS shell, or it is to be passed to an alternative
+       shell that accepts forward slash as a directory separator), use
+       forward slash instead of backslash as the directory separator.
+    2. If it is a variable that contains a filename, make sure you use a
+       macro-style variable name, rather than a
+       backslash-percent-character name.
+
+   Examples:
+
+  define test echo \fcontents(\%1)
+  define filename c:\mydir\blah.txt
+
+  test c:\\mydir\\blah.txt  ; Literal filename with double backslashes
+  c:\mydir\blah.txt
+
+  test c:/mydir/blah.txt    ; Literal filename with forward slashes
+  c:/mydir/blah.txt
+
+  test \m(filename)         ; Variable
+  c:\mydir\blah.txt
+
+   But what if you don't like these rules and you still want to pass a
+   literal filename containing single backslashes to a macro? This is
+   possible too, but a bit tricky: turn command quoting off before
+   invoking the macro, and then turn it back on inside the macro.
+   Example:
+
+  define test set command quoting on, echo \fcontents(\%1)
+
+  set command quoting off
+  test c:\mydir\blah.txt
+  c:\mydir\blah.txt
+
+   Upon return from the macro, command quoting is back on (since the
+   macro turned it on).
+
+   Obviously this trick can not be used if the filename is stored in a
+   variable, since it prevents the variable from being evaluated.
+     _________________________________________________________________
+
+    1.11.6. Passing DOS File Names from Macro Parameters to the DOS Shell
+
+   Now suppose you need to pass a DOS filename to a macro, and the macro
+   needs to pass it, in turn, to the Windows shell via (say) Kermit's RUN
+   command. This works too:
+
+  define xrun run \fcontents(\%1)
+  xrun c:\\windows\\command\\chkdsk.exe
+
+   (or you can use the SET COMMAND QUOTING OFF / ON technique described
+   above to avoid the double backslashes.) But..
+
+  xrun c:/windows/command/chkdsk.exe
+
+   does not work if the Windows shell does not recognize "/" as a
+   directory separator. If there is a chance that a filename might be
+   passed to the macro in this form, the macro will need to convert it to
+   a form acceptable to the shell:
+
+  define xrun run \freplace(\fcontents(\%1),/,\\)
+
+   Here we replace all occurrences (if any) of "/" in the argument with
+   "\" prior to issuing the RUN command. Of course, in order to specify
+   "\" as a literal character in the \freplace() argument list, we have
+   to double it.
+     _________________________________________________________________
+
+    1.11.7. Passing DOS Filenames to Kermit from the Shell
+
+   As noted in the manual, the \&@[] array contains Kermit's command-line
+   arguments. Suppose one of these arguments, say \&@[3], is a DOS
+   filename such as C:\FOO\BAR\BAZ\OOFA.TXT. (Note: In C-Kermit 7.0 and
+   K95 1.1.18 and later, command-line arguments after "=" or "--" are
+   also available in the top-level \%1..9 variables; see [360]Section
+   7.5.)
+
+   Of course you can eliminate any problems by using forward slashes
+   rather than backslashes in the filename, but sometimes this is not
+   possible, as when the Kermit command line is being generated by
+   another program than can only generate "native" format DOS filenames.
+
+   As noted in the manual, "\%x" variables and \&x[] arrays are always
+   evaluated "all the way" (recursively). If the contents of one of these
+   variables contains backslashes, this causes another level of
+   evaluation.
+
+   There is another kind of variable, which is evaluated only "one level
+   deep". You can use this to prevent interpretation of the backslashes
+   in the filenames. Example:
+
+  assign filename \fcontents(\&@[3])  ; Transfer contents
+  ...
+  send \m(filename)
+
+   Or, more simply:
+
+  send \fcontents(\&@[3])
+     _________________________________________________________________
+
+  1.12. Debugging
+
+   The debug log is produced when you give a "log debug" command. This is
+   normally done at the request of the Kermit help desk, for forwarding
+   to the Kermit developers for analysis as a last resort in
+   troubleshooting problems. (Last resort because it can grow quite huge
+   in a very short time.) In cases where timing information is critical
+   to understanding a problem, you can tell C-Kermit to put a timestamp
+   on each debug log line by giving the command:
+
+  SET DEBUG TIMESTAMP ON
+
+   At any time before or after activating the debug log (SET DEBUG
+   TIMESTAMP OFF turns off timestamping). Timestamps can be turned off
+   and on as desired while logging. Obviously, they increase the size and
+   growth rate of the log significantly, and so should be used sparingly.
+   Timestamps are of the form hh:mm:ss.xxx, where .xxx is thousands of a
+   second (but is included only on platforms that include this feature).
+     _________________________________________________________________
+
+  1.13. Logs
+
+   In UNIX C-Kermit and in K-95, you can now direct any log to a pipe.
+   This not only lets you send your logs to places other than disk files,
+   but also lets you customize them to any desired degree.
+
+   LOG { DEBUG, PACKETS, SESSION, TRANSACTION, CONNECTION } { file, pipe
+          } ...
+          A "pipe" is the name of a command, preceded by a vertical bar.
+          If the pipe contains any spaces, it must be enclosed in braces.
+
+   Here are some examples for UNIX (always remember the importance of
+   getting the UNIX shell quoting rules right):
+
+   LOG TRANSACTIONS |lpr
+          This sends the transaction log to the default UNIX printer,
+          rather than to a file (use "lp" rather than "lpr" if
+          necessary).
+
+   LOG TRANSACTIONS {| myfilter > t.log}
+          For those who don't like the format of the transaction log, or
+          want to extract certain information from it; write your own
+          output filter.
+
+   LOG SESSION {| lpr -Plaserwriter}
+          This sends the session log to a specific UNIX printer, rather
+          than to a file. Note the braces around the pipeline. These are
+          required because it contains spaces.
+
+   LOG DEBUG {| tail -100 > debug.log}
+          This causes the debug log file to contain only the final 100
+          lines. Suppose C-Kermit crashes under some unpredictable
+          circumstances, and you need a debug log to catch it in the act.
+          But the debug log can grow to huge proportions very quickly,
+          possibly filling up the disk. Piping the debug log through
+          "tail" results in keeping only the last 100 lines (or other
+          number of your choice).
+
+   LOG DEBUG {| grep "^TELNET" > debug.log}
+          This one shows how to log only Telnet negotiations. Piping the
+          debug log through grep or egrep lets you log only specific
+          information, rather than everything. "man grep" for further
+          info.
+
+   LOG DEBUG {| gzip -c > debug.log.gz}
+          Creates a full debug log, but compressed by gzip to save space.
+
+   LOG PACKETS {| tr "\\01" "X" | cut -c9- > packet.log}
+          This one writes the regular packet log, but translates the
+          Ctrl-A that starts each packet to the letter "X" and removes
+          the s-nn-nn- notation from the beginning of each line. Note the
+          double backslash (normal Kermit quoting rules). "man tr" and
+          "man cut" for further info.
+
+   See [361]Section 2.12 for information about the new connection log.
+     _________________________________________________________________
+
+  1.14. Automatic File-Transfer Packet Recognition at the Command Prompt
+
+   Beginning in version 7.0, C-Kermit can recognize Kermit (and in some
+   cases also Zmodem) file-transfer packets while at its command prompt.
+   This is convenient (for example), if you escaped back from a remote
+   Kermit program and told the local Kermit program to send a file, but
+   forgot to tell the remote Kermit program to receive it (and the local
+   Kermit did not have the "send a Kermit receive command" feature
+   available). This feature is controlled by the following command:
+
+   SET COMMAND AUTODOWNLOAD { ON, OFF }
+          When ON, which is the default, the command parser recognizes
+          Kermit packets when Kermit is in remote mode. An S packet makes
+          it go into receive mode, an I packet makes it go into server
+          mode. When OFF, packet recognition is disabled and the behavior
+          when a packet is received at the command prompt is as it was in
+          C-Kermit 6.1 and earlier (namely to print an error message).
+
+   COMMAND AUTODOWNLOAD is the command-mode equivalent of TERMINAL
+   AUTODOWNLOAD, which is effective during CONNECT mode.
+     _________________________________________________________________
+
+  1.15. The TYPE Command
+
+   The TYPE command now accepts a selection of optional switches
+   ([362]Section 1.5), and also sets several variables.
+
+   Syntax: TYPE [ switches... ] filename
+
+   Variables:
+
+   \v(ty_ln)
+          Line number of current line (during TYPE command; see /PREFIX)
+
+   \v(ty_lc)
+          Line count of file most recently TYPEd.
+
+   \v(ty_mc)
+          Match count of file most recently TYPEd (see /MATCH).
+
+   Switches:
+
+   /PAGE
+          If /PAGE is included, Kermit pauses at the end of each
+          screenful and issues a "more?" prompt. You may press the space
+          bar to view the next page (screenful), or press "q" or "n" to
+          return to the C-Kermit prompt. If this switch is given, it
+          overrides the COMMAND MORE-PROMPTING setting for this command
+          only. If it is not given, paging is according to COMMAND
+          MORE-PROMPTING.
+
+   /NOPAGE
+          Do not pause at the end of each screenful; show the whole file
+          (or all selected lines) at once. If this switch is given, it
+          overrides the COMMAND MORE-PROMPTING setting for this command
+          only. If it is not given, paging is according to COMMAND
+          MORE-PROMPTING.
+
+   /HEAD[:n]
+          Only show the first n lines of the file (where n is a number).
+          If n is omitted, 10 is used.
+
+   /TAIL[:n]
+          Only show the last n lines of the file (where n is a number).
+          If nis omitted, 10 is used. Note: /HEAD and /TAIL can't be
+          combined; if you give both switches, only the most recent one
+          is used.
+
+   /MATCH:pattern
+          Only type lines from the file that match the given pattern (see
+          [363]Section 4.9.1 for pattern notation). UNIX users familiar
+          with grep should note a significant difference: there is no
+          implied "*" at the beginning and end of the pattern. Thus:
+
+  TYPE /MATCH:foo    Lists lines whose entire contents are "foo".
+  TYPE /MATCH:foo*   Lists lines that start with "foo".
+  TYPE /MATCH:*foo   Lists lines that end with "foo".
+  TYPE /MATCH:*foo*  Lists lines that have "foo" anywhere in them.
+
+          /HEAD and /TAIL apply after /MATCH, so "type /tail:20
+          /match:x*" shows the last 20 lines in the file that start with
+          "x".
+
+   /PREFIX:string
+          Print the given string at the beginning of each line. The
+          string may be a constant, a variable, or a quoted variable. If
+          it's an unquoted variable, its value at the time the TYPE
+          command was given is used as a constant. If it is a quoted
+          variable, it is re-evaluated for each line; a useful variable
+          for this context is \v(ty_ln) (the line number of the current
+          line being typed). If the prefix is to include spaces, it must
+          be enclosed in braces. Examples:
+
+        type /prefix:{oofa.txt: } /match:*thing* oofa.txt
+                Prints all lines in oofa.txt that contain "thing" with
+                the filename itself as the prefix (similar to UNIX grep).
+
+        type /prefix:{\v(time). } oofa.txt
+                Prefixes each line of oofa.txt with the time at which the
+                TYPE command was given (one backslash)
+
+        type /prefix:{\\v(time). } oofa.txt
+                Prefixes each line of oofa.txt with the time at which
+                that line is being typed (two backslashes).
+
+        type /prefix:{\\v(ty_ln). } oofa.txt
+                Prefixes each line of oofa.txt with its line number.
+
+        type /prefix:{\\flpad(\\v(ty_ln),4). } oofa.txt
+                Same as the previous example, except the line number is
+                right-adjusted in a 4-column field.
+
+   /WIDTH[:n]
+          Truncates each line at column n (which must be a number) prior
+          to printing it. This option can be used for long lines when you
+          don't want them to wrap. If nis omitted, your current screen
+          width is used.
+
+   /COUNT
+          Counts lines and -- if /MATCH was included, matches -- but does
+          not print any lines from the file. The line and match count is
+          shown at the end, and the variables \v(ty_lc) and \v(ty_lm) are
+          set accordingly.
+
+   SET OPTIONS TYPE { /PAGE, /NOPAGE, /WIDTH:n }
+          Sets the paging default for TYPE commands, which can be
+          overridden in any particular TYPE command by including the
+          desired switch.
+
+   If a TYPE command is given with no switch, and no SET OPTIONS TYPE
+   selection is in effect, paging is according to your COMMAND
+   MORE-PROMPTING setting (SHOW COMMAND).
+     _________________________________________________________________
+
+  1.16. The RESET Command
+
+   The RESET command, added in 7.0, closes all open files and logs, but
+   does not affect the open connection (if any).
+     _________________________________________________________________
+
+  1.17. The COPY and RENAME Commands
+
+   As of C-Kermit 7.0, in the UNIX version only, the COPY and RENAME
+   commands are built in and do not call the underlying platform's COPY
+   or RENAME command. This allows them to work in "NOPUSH" versions and
+   other circumstances where it can't access system commands, and it
+   allows file copying and renaming to be done portably in scripts. The
+   characteristics of the built-in COPY or RENAME include:
+     * It fails if the source file is a directory or is wild or lacks
+       read access.
+     * It fails if the source file is the destination file.
+     * It allows the destination file to be a directory, in which case
+       the source file is copied (or renamed) into it with the same name.
+     * It overwrites an existing destination file if its permission
+       allows.
+     * It sets the new file's permission according to umask but also
+       carries forward the source file's execute permission bits if the
+       destination file did not already exist.
+     * It fails if interrupted by Ctrl-C.
+     * Upon error, it prints an appropriate message.
+     * It returns standardized error codes that can be tested by IF
+       SUCCESS / FAIL.
+
+   These commands now also accept the following switches:
+
+  /LIST (/LOG, /VERBOSE)    = Print "file1 => file2 (OK)" (or error message).
+  /NOLIST (/NOLOG, /QUIET)  = Don't print anything (except error messages).
+
+   /NOLIST is the default.
+
+   The same built-in code is used by the UNIX C-Kermit server to execute
+   REMOTE COPY commands (except in this case no switches are available).
+
+   The COPY command also accepts the following additional switches. When
+   any of these are given (and they can be used in any combination except
+   /SWAP and /APPEND), some of the checks listed above are relaxed, and
+   thus it might be possible to get into trouble in certain cases, e.g.
+   when the source and target files are the same file:
+
+  /APPEND                   = Append source file to destination file.
+  /SWAP-BYTES               = Swap bytes (see [364]Section 6.6.5).
+  /FROMB64                  = Decode the source file from Base64 encoding.
+  /TOB64                    = Encode the target file in Base64.
+
+   Base64 is the encoding commonly used for enclosures in Internet email.
+     _________________________________________________________________
+
+  1.18. The MANUAL Command
+
+   The MANUAL command can be used to access the appropriate Kermit manual
+   or other manual. The general syntax is:
+
+   MANUAL [ string ]
+          If the string is omitted, C-Kermit asks the underlying system
+          to access the C-Kermit manual using whatever method is
+          appropriate for the system.
+
+   The specific action depends on the system. In UNIX, a "man" command is
+   issued; "kermit" is the default argument but other manual topics may
+   be specified. If the "man" command allows index or string searching,
+   the appropriate syntax may be included.
+
+   In Kermit 95, the MANUAL command brings up the HTML online K95 manual.
+
+   In VMS and elsewhere, "man" is simply translated to "help", with a
+   default argument of "kermit"; other and/or additional arguments may be
+   included according to the definition of the system's "help" command.
+
+   Correct operation of the "man" command in C-Kermit depends on the
+   appropriate man page or help topic having been installed in the right
+   place with the right permissions and format.
+     _________________________________________________________________
+
+  1.19. String and Filename Matching Patterns
+
+   A pattern is a string that includes special notation for matching
+   classes or sequences of characters. C-Kermit 7.0 / K95 1.1.19 supports
+   patterns in several places:
+
+     * Filenames ([365]Section 4.9)
+     * SWITCH case labels ([366]Section 7.18)
+     * The new IF MATCH statement ([367]Section 7.4)
+     * TYPE /MATCH ([368]Section 1.15)
+     * SET FILE TEXT-PATTERNS and BINARY-PATTERNS ([369]Section 4.3)
+     * The \fsearch() and \farraylook() functions ([370]Sections 7.3 and
+       [371]7.10.7)
+     * The \fpattern() function used with [M,RE]INPUT ([372]Section 7.1)
+
+   Patterns are also called wildcards, especially when used for filename
+   matching. C-Kermit's pattern syntax is explained in [373]Section
+   4.9.1, and also by the HELP WILDCARDS command.
+     _________________________________________________________________
+
+  1.20. Multiple Commands on One Line
+
+   As of C-Kermit 7.0, commands can be grouped together on one line by
+   separating the commands with commas and enclosing the list in braces.
+   For example:
+
+  C-Kermit> { echo One, echo Two, echo Three }
+  C-Kermit> do { echo One, echo Two, echo Three }
+
+   Command lists can be nested:
+
+  [ do ] { echo One, echo Two, if true { echo A, echo B}, echo Three }
+
+   and the END command works as it does in macros:
+
+  [ do ] { echo One, echo Two, if true end, echo Three }
+
+   The "one line" stricture is, of course, pliant to line-continuation
+   conventions, namely that lines ending in hyphen (-) or left brace ({)
+   are to be continued. Thus the first example can also be rendered:
+
+  [ do ] {
+      echo One
+      echo Two
+      echo Three
+  }
+
+   (the "do" is optional).
+     _________________________________________________________________
+
+  1.21. What Do I Have?
+
+   C-Kermit can be built for hundreds of different platforms with
+   practically countless configuration options. Certain commands might
+   not be available in certain configurations, etc. Even on the same
+   platform, different builds are possible: "maximum functionality",
+   "minimum size", "maximum performance", and so on. You can find out a
+   lot about the configuration of your C-Kermit program with the SHOW
+   FEATURES command. Of course, a lot of what it says, especially in the
+   bottom part, might seem like gibberish, but can be deciphered with a
+   Rosetta Stone (such as the C-Kermit source or the [374]ckccfg.txt
+   file). In any case, the output from SHOW FEATURES might easily explain
+   why some expected feature is missing, or some buffer is smaller than
+   expected. Here's a sample of the bottom section for the SunOS version:
+
+C-Kermit 7.0.196, 1 Jan 2000
+
+Major optional features included:
+ Network support (type SHOW NET for further info)
+ Telnet Kermit Option
+ Hardware flow control
+ External XYZMODEM protocol support
+ Latin-1 (West European) character-set translation
+ Latin-2 (East European) character-set translation
+ Cyrillic (Russian, Ukrainian, etc) character-set translation
+ Greek character-set translation
+ Hebrew character-set translation
+ Japanese character-set translation
+ Unicode character-set translation
+ Pseudoterminal control
+ REDIRECT command
+ RESEND command
+ Fullscreen file transfer display
+ Control-character unprefixing
+ Streaming
+ Autodownload
+
+Major optional features not included:
+ No Kerberos(TM) authentication
+ No SRP(TM) (Secure Remote Password) protocol
+ No Secure Sockets Layer (SSL) protocol
+ No Transport Layer Security (TLS) protocol
+ No encryption
+ No X Windows forwarding
+
+Host info:
+ Machine:    sun4m
+ Model:      (unknown)
+ OS:         SunOS
+ OS Release: 4.1.3_U1
+ OS Version: 4
+
+Target: sunos41gsc
+GCC version: 2.7.2
+Compiled Dec 31 1999 10:38:54, options:
+ __GNUC__ __STDC__ _POSIX_JOB_CONTROL _SC_JOB_CONTROL ARRAYREFLEN=1024 BIGBUFOK
+ BROWSER BSD4 CK_ANSIC CK_APC CK_AUTODL CK_CURSES CK_DNS_SRV CK_ENVIRONMENT
+ CK_FAST CK_LOGIN CK_MKDIR CK_NAWS CK_PCT_BAR CK_PERMS CK_RECALL CK_RTSCTS
+ CK_SPEED CK_TIMERS CK_TMPDIR CK_TTGWSIZ CK_TTYFD CK_WREFRESH CKEXEC
+ CKFLOAT=double CKGHNLHOST ckmaxfiles=64 CKMAXOPEN=64 CKMAXPATH=1023 CKREALPATH
+ CKREGEX CKSYSLOG CKTUNING CMDBL=32763 CMDDEP=64 CONGSPD DCMDBUF DIRENT DYNAMIC
+ FNFLOAT FORDEPTH=32 GFTIMER HADDRLIST HDBUUCP IFDEBUG IKS_OPTION IKSDB
+ IKSDCONF INBUFSIZE=32768 INPBUFSIZ=4096 MAC_MAX=16384 MACLEVEL=128 MAXDDIR=32
+ MAXDNUMS=4095 MAXGETPATH=128 MAXTAKE=54 MAXWLD=102400 MSENDMAX=1024 NETCMD
+ NETCONN NETPTY NOKVERBS NOSETBUF OBUFSIZE=32768 PARSENSE PATTERNS PIPESEND
+ RENAME RLOGCODE SAVEDUID SELECT SIG_V SOL_SOCKET sparc STREAMING sun SUNOS4
+ SYSTIMEH TCPSOCKET TIMEH TLOG TNCODE TTLEBUF TTSPDLIST UIDBUFLEN=256 UNIX
+ UNPREFIXZERO USE_LSTAT USE_MEMCPY VNAML=4096 WHATAMI XFRCAN Z_MAXCHAN=46
+ z_maxchan=46 ZXREWIND
+
+ byte order: big endian
+
+ sizeofs: int=4 long=4 short=2 char=1 char*=4 float=4 double=8
+
+ floating-point: precision=16 rounding=1
+
+   Without going into detail about what all the notation means, notice a
+   couple things:
+
+     * The Options section shows symbols ("macros") in effect during
+       compilation, together with their values (for those that have
+       values). The options are listed in alphabetical order to make any
+       particular option easier to find.
+     * MAXWLD is the maximum number of files that a wildcard can expand
+       to.
+     * Anything starting with "NO" is a feature (or something other than
+       a feature) that has been deliberately "compiled out", or omitted.
+     * Important items for script writers include: CMDBL=32763 (the size
+       of the command buffer and therefore the maximum length for a macro
+       or variable definition; CMDDEP=64 (the limit on recursion depth);
+       FORDEPTH=32 (the nesting limit on FOR loops); INBUFSIZE=32768 (the
+       size of the INPUT command circular buffer); MAC_MAX=16384 (the
+       maximum number of macros), etc.
+
+   See the [375]ckccfg.txt file for details.
+     _________________________________________________________________
+
+  1.22. Generalized File Input and Output
+
+   C-Kermit 7.0 adds a new generalized I/O system for stream files,
+   augmenting (and to some extent, overlapping with) the older OPEN,
+   READ, WRITE, and CLOSE commands. In the new file i/o system, which can
+   be used simultaneously with the old one, all commands are grouped
+   together under the new FILE keyword, and some related functions and
+   variables are added.
+
+    1.22.1. Why Another I/O System?
+
+   The well-known LOG, OPEN, READ, WRITE, and CLOSE commands have the
+   following restrictions:
+
+    1. Only one READ file and one WRITE file can be open at a time.
+    2. The READ and WRITE commands are strictly line oriented.
+    3. These commands can not be used with binary files.
+    4. They do not support read/write access or random access.
+    5. The syntax is a bit counterintuitive for programmers.
+
+   The new file i/o system allows multiple files to be open at once, in
+   any desired combination of modes (read/write/append) supported by the
+   operating system, for line, block (record), or character i/o, for
+   sequential or random access, using consistent syntax and conventions.
+
+   The new system, however, does not replace the old one, since the old
+   system still must be used for:
+
+    1. The session, packet, debug, transaction, and connection logs.
+    2. Reading and writing commands rather than files.
+    3. Existing scripts.
+
+   The new system works only with regular files, not with commands or
+   pipes or mailboxes or pseudoterminals. No special provisions are made
+   in the FILE commands for handling devices or network connections, nor
+   for preventing you from trying to open them; if the underlying
+   operating system treats them like regular stream disk files, the FILE
+   commands (except, of course SEEK, REWIND, and COUNT) might work with
+   them. (In C programming terms, the FILE commands are, at present,
+   nothing more than a front end to fopen() / fread() / fwrite() /
+   fclose() and friends, which are a portable API to sequential files,
+   but this might change in the future for platforms like VMS and VOS
+   that have more complicated file systems.)
+
+   Definitions:
+
+   Channel
+          A number assigned to a file when it is opened, by which it must
+          be referred to in all input/output operations.
+
+   Read/Write Pointer
+          The current position in an open file, expressed as the 0-based
+          byte count from the beginning.
+     _________________________________________________________________
+
+    1.22.2. The FILE Command
+
+   FILE keyword [ switches ] channel [ data ]
+          The keyword specifies the function: FILE OPEN, FILE READ, FILE
+          WRITE, FILE CLOSE, etc. For convenience (and for familiarity to
+          C programmers), the two-word FILE commands can be shortened to
+          the single words FOPEN, FREAD, FWRITE, FCLOSE, and so on.
+          Switches are optional, and modify or amplify the requested file
+          function.
+
+   As in C, Fortran, and other programming languages, open files are
+   referred to by "channels", integers such as 0, 1, 2, 3, and so on. A
+   channel number is assigned when you open a file. The number of
+   available channels depends on the underlying operating system, and can
+   be seen in the variable:
+
+  \v(f_max)
+
+   or by giving the FILE LIST (FLIST) command. Channels are discussed in
+   greater detail in [376]Section 1.22.4.
+
+   FILE command errors can be caught with IF FAIL after the FILE command.
+   In addition, the \v(f_error) variable is set to the completion code of
+   the command: 0 if no error, or a negative number if there was an
+   error. The error codes are listed in [377]Section 1.22.5.
+
+   The command to open a file is:
+
+   FILE OPEN [ switches ] variable filename
+          Opens a file for the type of access specified by the switches,
+          or for read-only access if no switches are given. Upon success,
+          a channel number is assigned to this file and stored in the
+          given variable so you can refer to the open file in subsequent
+          i/o commands. If the file can not be opened, the FILE OPEN
+          command fails. Synonym: FOPEN.
+
+   The FILE OPEN switches are:
+
+   /READ
+          Open the file for read access. If no switches are given, /READ
+          is assumed. If the file does not exist or can't be opened for
+          read access, the FILE OPEN command fails.
+
+   /WRITE
+          Allow writing. If a file of the same name already exists, it is
+          overwritten unless /READ or /APPEND is also included. If a file
+          of the given name does not exist, it is created.
+
+   /APPEND
+          Equivalent to /WRITE, except that if the file exists, it is not
+          destroyed. The read/write pointer is set to the end of the
+          file, so unless you change it with FILE SEEK or REWIND (see
+          below), the first FILE WRITE command adds to the end of the
+          file, preserving what was there already. If /WRITE is also
+          given, it is ignored.
+
+   /BINARY
+          Open the file in "binary" mode, rather than text mode. This
+          switch is meaningless (but still can be used) in UNIX. In VMS,
+          Windows, and OS/2, it inhibits end-of-line processing and
+          conversion, and so should be used for binary files and/or files
+          that are to be accessed in record or character mode rather than
+          line by line.
+
+   The variable for the channel number can be any kind of variable: the
+   \%x kind, a macro name, or an array element. But it must be a
+   variable, not a number -- C-Kermit assigns the channel number; you
+   can't tell it what number to use.
+
+   Example:
+
+  FILE OPEN \%c oofa.txt                  ; Open oofa.txt for reading.
+  IF FAIL exit 1 Can't open oofa.txt      ; Always check to see if it worked.
+  ECHO oofa.txt: channel = \%c
+
+   If the file oofa.txt is opened successfully, a channel number is
+   assigned to the variable \%c. Here's another example using a macro
+   name for the channel number:
+
+  FILE OPEN channel oofa.txt              ; Open oofa.txt for reading.
+  IF SUCCESS ECHO oofa.txt: channel = \m(channel)
+
+   Switches can be combined when it makes sense and the underlying
+   operating system allows it. For example, to open a file in binary mode
+   for reading and writing (sometimes called "update"):
+
+  FILE OPEN /READ /WRITE /BINARY \%c budget.db
+
+   Some combinations might be allowed, others not. For example /READ
+   /APPEND will usually not be allowed. /WRITE /APPEND is treated as
+   /APPEND.
+
+   A major advantage of the new system over the older one is that you can
+   have multiple files open at once. Suppose, for example, that you want
+   to open all the files in a certain directory at once:
+
+  .\%n := \ffiles(/usr/olga*,&f)          ; Get file list into array.
+  if ( > \%n \v(f_max) ) {                ; Make sure there aren't too many.
+      exit 1 {\v(dir): \%n = Too many files}
+  }
+  declare \&c[\%n]                        ; Make array for channel numbers.
+  for \%i 1 \%n 1 {                       ; Loop to open every file...
+      file open \&c[\%i] \&f[\%i]         ; Try to open this one
+      if fail exit 1 Open error: \&f[\%i] ; Check for failure
+  }
+
+   If this loop completes successfully, the \&c[] array will contain \%n
+   channel numbers of open files in elements 1 through \%n.
+
+   Any file that you open with FILE OPEN stays open until Kermit exits,
+   or you close it explicitly. The command to close a file is:
+
+   FILE CLOSE { ALL, channel }
+          If a channel number is given and the channel refers to an open
+          file, the file is closed and the channel is freed for reuse; if
+          the channel does not refer to an open file, an error message is
+          printed and the command fails. If ALL is specified instead of a
+          specific channel, all files opened with FILE OPEN are closed
+          and if all open files were closed successfully (even if no
+          files were open), the command succeeds; if any open file could
+          not be closed, the command fails; however, all open files that
+          could be closed are still closed. Synonym: FCLOSE.
+
+   FILE CLOSE might fail because, for example, the disk filled up or a
+   quota was exceeded. Example:
+
+  fopen /write \%c new.txt                ; Open new.txt for writing.
+  if fail exit 1                          ; Check for error.
+  fclose \%c                              ; Close the file we just opened.
+
+   This creates a 0-length file called new.txt.
+
+   Note that FILE OPEN /WRITE (without /READ or /APPEND) always creates a
+   new file, and therefore destroys any file with the same name that
+   might already exist (assuming you have permission to delete it). To
+   avoid overwriting existing files, simply check first:
+
+  if exist new.txt exit 1 {Fatal - new.txt already exists}
+  fopen /write \%c new.txt
+  if fail ...
+
+   The next two commands give information about open files:
+
+   FILE STATUS channel
+          Tells the name of the file, if any, open on the given channel
+          and the switches it was opened with. The read/write pointer is
+          also shown; this is where the next read or write will occur;
+          "[EOF]" is shown if the current position in the open file is
+          the end -- i.e. the next read will fail if the file was opened
+          in /READ mode; the next write will add material to the end. The
+          current line number (0-based) is also shown if known. The FILE
+          STATUS command succeeds if the channel is open, and fails if
+          there is no open file on the given channel, or if the channel
+          number is invalid or out of range. Synonym: FSTATUS.
+
+   FILE LIST
+          Lists the channel number and name of each open file, along with
+          its OPEN modes (R, W, A, B, RW, etc) and its current read/write
+          pointer or "[EOF]" if it is at the end. Also tells the number
+          of files currently opened with FILE OPEN, plus the maximum
+          number of open files allowed by the system and the maximum
+          number allowed for FILE OPEN. Synonym: FLIST.
+
+   Next come the commands for reading and writing files:
+
+   FILE READ [ switches ] channel [ variable ]
+          Reads data from the file on the given channel number into the
+          variable, if one was given; if no variable was given, the
+          result is printed on the screen. IMPORTANT: The variable should
+          normally be a macro name rather than a \%x or \&x[] variable if
+          you want backslash characters in the file to be taken literally
+          (see pp.408-412 of [378]Using C-Kermit for an explanation; you
+          can also read into a \%x or \&x[] variable, but then you must
+          remember to protect future references to by \fcontents() if you
+          don't want C-Kermit to process any backslashes it might
+          contain). The desired amount of data (according to the
+          switches) is read from the file at the current read/write
+          pointer, and upon completion the read/write position is updated
+          to first byte after the data that was read, no matter what
+          switches were given. Synonym: FREAD.
+
+   FILE WRITE [ switches ] channel text
+          Writes the given text to the file on the given channel number.
+          The text, of course, can be literal text or a variable, or any
+          combination. If the text might contain leading or trailing
+          spaces, it must be enclosed in braces if you want to preserve
+          them. Synonym: FWRITE.
+
+   Before proceeding, a caution about the NUL character. C-Kermit is so
+   named because it is a Kermit program written in the C language. In C,
+   character strings are represented as a sequence of non-NUL bytes
+   terminated by a NUL byte (a byte in which all bits are 0). Thus a C
+   string can not contain NUL bytes; it always ends with the first NUL
+   byte. C-Kermit variables are implemented as C strings and therefore
+   can't contain NUL bytes either, so the FILE READ and FILE WRITE
+   commands do not handle files or strings that contain NUL bytes, except
+   when the /CHARACTER switch is included with the FILE READ or WRITE
+   command, or when /LPAD:0 or /RPAD:0 is given with the FILE WRITE
+   command; these switches are explained below.
+
+   Also note that Kermit can not be used read or write binary numbers in
+   the machine's internal format (integer or floating-point); in general,
+   numbers can be processed only when represented as numeric or
+   floating-point strings.
+
+   FILE READ switches are:
+
+   /LINE
+          Specifies that a line of text is to be read. A line is defined
+          according to the underlying operating system's text-file
+          format. For example, in UNIX a line is a sequence of characters
+          up to and including a linefeed, or the end of the file, which
+          ever comes first. The line terminator (if any) is removed
+          before assigning the text to the variable. If no switches are
+          included with the FILE READ command, /LINE is assumed. Normally
+          this switch should not be used with files opened in /BINARY
+          mode (but nothing prevents it either).
+
+   /SIZE:number
+          Specifies that the given number of bytes (characters) is to be
+          read. The actual number of bytes returned will be less if the
+          end of file is reached (or a NUL byte is encountered). For
+          example, if a file is 514 bytes long, FILE READ /SIZE:512
+          returns 512 bytes the first time and 2 bytes the second time.
+          FILE READ /SIZE provides a kind of "record i/o" for files that
+          do not necessarily contain lines. The resulting block of
+          characters is assigned to the variable without any editing.
+          Synonym: /BLOCK.
+
+   /CHARACTER
+          Equivalent to /SIZE:1. If FILE READ /CHAR succeeds but the
+          variable is empty, this indicates a NUL byte was read. Synonym:
+          BYTE.
+
+   FILE WRITE switches are:
+
+   /LINE
+          Specifies that an appropriate line terminator is to be added to
+          the end of the text. If no switches are included, /LINE is
+          assumed.
+
+   /SIZE:number
+          Specifies that the given number of bytes (characters) is to be
+          written. If the given text is longer than the requested size,
+          it is truncated; if is shorter, it is padded according /LPAD
+          and /RPAD switches. Synonym: /BLOCK.
+
+   /LPAD[:value]
+          If /SIZE was given, but the text is shorter than the requested
+          size, the text is padded on the left with sufficient copies of
+          the character whose ASCII value is given to write the given
+          length. If no value is specified, 32 (the code for Space) is
+          used. The value can also be 0 to write the indicated number of
+          NUL bytes. If /SIZE was not given, this switch is ignored.
+
+   /RPAD[:value]
+          Like LPAD, but pads on the right.
+
+   /CHARACTER
+          Specifies that one character should be written. If the text is
+          empty or not given, a NUL character is written; otherwise the
+          first character of text is given. Synonym: /BYTE.
+
+   /STRING
+          Specifies that the text is to be written as-is, with no
+          terminator added.
+
+   Here's an example in which we copy a text file line by line:
+
+  file open /read \%c oofa.txt            ; Open input file
+  if fail exit 1 Can't open input file    ; Check that it's open
+  file open /write \%d new.txt            ; Open output file
+  if fail exit 1 Can't open output file   ; Check
+  while true {                            ; Loop to copy lines
+      file read /line \%c line            ; Read a line
+      if fail break                       ; Assume failure = end of file
+      file write /line \%d {\m(line)}     ; Write the line to output file
+      if fail exit 1 Write failure        ; Failure here is fatal
+  }
+  file close \%c                          ; Close the two files
+  file close \%d
+
+   Note that since /LINE is the default for both FILE READ and FILE
+   WRITE, it can be omitted as in the following example, where we also
+   use the short names for the FILE commands.
+
+  fopen /read \%c oofa.txt                ; Open input file
+  if fail exit 1 Can't open input file    ; Check that it's open
+  fopen /write \%d new.txt                ; Open output file
+  if fail exit 1 Can't open output file   ; Check
+  while true {                            ; Loop to copy lines
+      fread \%c line                      ; Read a line
+      if fail break                       ; Assume failure = end of file
+      fwrite \%d {\m(line)}               ; Write the line to output file
+      if fail exit 1 Write failure        ; Failure here is fatal
+  }
+  fclose \%c                              ; Close the two files
+  fclose \%d
+
+   Here's the same example using "record i/o" (the open and close
+   sequences are are omitted since they are the same as above). The
+   result is the same, but execution is much faster:
+
+  while true {                            ; Loop to copy blocks
+      fread /size:512 \%c block           ; Read a block into \%a
+      if fail break                       ; Assume failure = end of file
+      fwrite /string \%d {\m(block)}      ; Write the block to output file
+      if fail exit 1 Write failure        ; Failure here is fatal
+  }
+
+   Although record i/o is faster, it should not be used in line-oriented
+   applications, since it returns arbitrary chunks of the file to your
+   script, rather than lines. In this example, FWRITE /STRING is used
+   rather than FWRITE /SIZE:512 to avoid the last output block being
+   padded beyond the original file's length.
+
+   A file can also be copied character by character, but this is much
+   slower than line i/o and VERY much slower than block i/o:
+
+  while true {                            ; Loop to copy blocks
+      fread /char \%c c                   ; Read a character into c
+      if fail break                       ; Assume failure = end of file
+      fwrite /char \%d {\m(c)}            ; Write character to output file
+      if fail exit 1 Write failure        ; Failure is fatal
+  }
+
+   Although character i/o is slow, it is the only way to process files
+   that contain NUL characters (i.e. bytes composed of only zero bits).
+   In the example above, when "fread /char \%c c" returns a NUL, the c
+   variable is empty. But since the FREAD /CHAR command did not fail, we
+   know the result was really a NUL. FWRITE /CHAR, when given an empty
+   variable (or no variable at all) writes a NUL. Thus the loop above
+   will copy any file at all (very slowly). In non-copying applications,
+   NULs are detected like this:
+
+  fread /char \%c c
+  if fail (do something)
+  if not def c (a NUL byte was read)
+
+   Finally some advanced file operations:
+
+   FILE FLUSH channel
+          For output files only: commits all previous writes to disk, in
+          case the computer was buffering them. Synonym: FFLUSH.
+
+   FILE COUNT [ { /BYTES, /LINES, /LIST, /NOLIST } ] channel
+          By default, or if the /BYTES switch is given, counts the bytes
+          in the file, if any, open on the given channel. If the /LINES
+          switch is given, counts lines in the file. If the /LIST switch
+          is given, the result is printed. If the /NOLIST switch is
+          given, the result is not printed. /QUIET is a synonym for
+          /NOLIST. If neither /LIST nor /NOLIST is given, the result is
+          printed if the command is given at top level, i.e. not from a
+          command file or macro. In all cases, the result of the most
+          recent FILE COUNT command is stored in the variable
+          \v(f_count). Note that FILE COUNT /LINE works (and can only
+          work) by reading the entire file; expect it to take some time
+          if the file is large. Synonym: FCOUNT.
+
+   FILE REWIND channel
+          Moves the read/write pointer to the beginning of the file.
+          Equivalent to FILE SEEK channel 0. Synonym: FREWIND.
+
+   FILE SEEK [ switches ] channel { [{+,-}]number, LAST, EOF }
+          Moves the read/write pointer for the file on this channel to
+          the given position, which may be a byte (character) number or a
+          line number, expressed in either absolute or relative terms.
+          Switches:
+
+        /BYTE
+                The number given is a byte number. Synonym: /CHARACTER.
+
+        /LINE
+                The number given is a line number.
+
+        /ABSOLUTE
+                The number given is absolute.
+
+        /RELATIVE
+                The number given is relative to the current position.
+
+          By default, or if the /BYTE switch is given, the number is a
+          byte number (0 = first byte). If /LINE is given, the number is
+          a line number (0 = first line). EOF means to move to the end of
+          the file. LAST means to move to the last line or character of
+          the file, depending on whether it's a line or character seek.
+
+          If neither the /RELATIVE nor the /ABSOLUTE switch is given,
+          then if a signed number is given, the motion is relative to the
+          current position. An expression that evaluates to a negative
+          number is not considered signed for this purpose; that is, a
+          sign (+ or -) must be included as the first character of the
+          number in the command itself to force a relative seek (in the
+          absence of /RELATIVE or /ABSOLUTE).
+
+          If the number has no sign, or if the /ABSOLUTE switch is given,
+          the number represents an absolute position (relative to the
+          beginning of the file). Subsequent FILE READs or WRITEs will
+          take place at the new position.
+
+          If the read/write pointer is placed after the end of the file,
+          a subsequent FILE READ will fail, but a FILE WRITE will succeed
+          (possibly creating a file with "holes"). If a FILE SEEK /BYTE
+          command is given, the current line becomes unknown (unless the
+          position is 0) and subsequent FILE SEEK /RELATIVE /LINE
+          commands will fail until the next non-relative FILE SEEK /LINE
+          command is given. Synonym: FSEEK.
+
+   An absolute FILE SEEK to a negative position fails silently, as does a
+   relative seek to a position before the beginning of the file.
+
+   A caution about relative SEEKs: remember that the number is relative
+   to the current position. Whenever you read or write, this changes the
+   position. In each of the following examples, assume the file open on
+   channel \%c is positioned at line n (the FREAD target variable is
+   omitted for lack of space):
+
+  { FREAD \%c, FSEEK /LINE \%c -1, FREAD \%c }  <-- Reads line n twice
+  { FREAD \%c, FSEEK /LINE \%c +0, FREAD \%c }  <-- Reads lines n and n+1
+  { FREAD \%c, FSEEK /LINE \%c +1, FREAD \%c }  <-- Reads lines n and n+2
+  { FREAD \%c, FSEEK /LINE \%c -2, FREAD \%c }  <-- Reads lines n and n-1
+  { FREAD \%c, FSEEK /LINE \%c -3, FREAD \%c }  <-- Reads lines n and n-2
+
+   Another caution: Using FSEEK and FREAD /SIZE to repeatedly read the
+   same disk block (e.g. when sampling a database record that is
+   frequently updated) might not give you updated disk blocks due to the
+   internal buffering and caching of the C library (this probably varies
+   from one platform/compiler combination to another). If necessary you
+   can force a fresh disk read with a close/open sequence:
+
+  FCLOS \%c
+  FOPEN \%c samefilename
+  FSEEK \%c samespot
+  FREAD /SIZE:howmanybytes \%c variable
+     _________________________________________________________________
+
+    1.22.3. FILE Command Examples
+
+   To read the last 10 lines of a text file into an array:
+
+  fopen /read \%c oofa.txt                ; Open the file
+  if fail exit 1 Can't open oofa.txt      ; Always check for failure
+  dcl \&a[10]                             ; Declare a 10-element array
+  fcount /line \%c                        ; Count lines in the file
+  fseek /line \%c \v(f_count)-10          ; Seek to 10 lines from the end
+  if fail exit 1 Can't seek               ; Check for failure
+  for \%i 1 10 1 { fread \%c \&a[\%i] }   ; Read the last 10 lines
+  fclose \%c                              ; Close the file
+
+   Note that blank lines show up as empty (undefined) array elements, for
+   example if you give a "show array a" command at this point. This is
+   normal. You can still use these elements; e.g.:
+
+  for \%i 1 10 1 { echo \%i. \&a[\%i] }   ; Display the 10 lines
+
+   Here is how to read the last line of a file (already open on channel
+   \%c):
+
+  fseek /line \%c last                    ; Seek directly to last line
+
+   Alternatively:
+
+  fseek /line \%c eof                     ; Seek to end of file
+  fseek /line \%c -1                      ; Seek to beginning of last line
+
+   Alternatively:
+
+  fcount /line \%c                        ; Count the file's lines
+  fseek /line \%c \v(f_count)-1           ; Seek to last line
+  fread \%c                               ; Read it
+
+   To read every other line from the file (using relative SEEK), skipping
+   the first line:
+
+  fopen /read \%c oofa.txt                ; Open the file
+  while ( success ) {                     ; Loop through lines
+      fseek /line \%c +1                  ; Skip a line
+      if success fread \%c                ; Read & display a line
+  }
+  fclose \%c                              ; Close the file
+
+   Here is how to read the lines of a file in reverse order:
+
+  fopen /read \%c oofa.txt                ; Open
+  if fail exit 1                          ; Check
+  fseek /line \%c last                    ; Seek to last line
+  while success {                         ; Loop
+      fread \%c                           ; Read line
+      fseek /line \%c -2                  ; Seek backwards two lines
+  }
+  fclose \%c                              ; Close the file
+
+   The loop works because a relative SEEK outside the file fails.
+
+   It is also possible to use block i/o to manage random-access files
+   with fixed-length records (as long as they don't contain NUL
+   characters). Suppose, for example, you have a file of "card image"
+   records with fixed-field information about customers, such as:
+
+  Name:     Columns  1-32  (column numbers are 1-based)
+  Address:  Columns 33-72
+  Balance:  Columns 73-80
+
+   The records are indexed by customer number, starting with 0. There are
+   no line terminators separating them. Therefore the record for customer
+   number n starts at position nx 80 (\%n*80).
+
+   Now suppose we received a payment from customer number 173 and want to
+   update the balance:
+
+  .\%n = 173                               ; Customer (record) number
+  .\%a = 12.72                             ; Amount
+  fopen /read /write \%c customer.db       ; Open the file
+  if fail stop 1 OPEN FAILED: \f_errmsg()  ; Check
+  fseek /byte \%c 80*\%n                   ; Seek to record
+  fread /size:80 \%c r                     ; Read the record
+  if fail stop 1 READ FAILED: \f_errmsg()  ; Check (IMPORTANT)
+  .\%b := \fright(\m(r),8)                 ; Extract the balance
+  .\%b := \ffpadd(\%b,\%a,2)               ; Add the new payment
+  if fail stop 1 ARITHMETIC ERROR: \%b/\%a ; Catch bad records
+  .r := {\fleft(\m(r),72)\flpad(\%b,8)}    ; Update the record
+  fseek /byte \%c 80*\%n                   ; Reposition to same spot
+  fwrite /size:80 \%c {\m(r)}              ; Replace the record
+  if fail stop 1 WRITE FAILED: \f_errmsg() ; Check
+  fclose \%c                               ; Close the file
+
+   REMEMBER: Using FILE SEEK to move beyond the end of file can result in
+   a file with holes when writing; when reading, an end-of-file error
+   will occur -- be sure to check for it.
+     _________________________________________________________________
+
+    1.22.4. Channel Numbers
+
+   C-Kermit's channel numbers are integers from 0 to some
+   platform-dependent limit, such as 46 or 1985 (the value of \v(f_max)).
+   This is the limit placed by the operating system on the number of
+   files that may be opened by one process or user or job, minus the
+   standard input, output, and error files, and minus the number of files
+   reserved by C-Kermit for logs, OPEN READ and WRITE, and file transfer
+   (and maybe some command files -- the \v(f_max) number can't be exact).
+
+   Although you must include a variable in the FILE OPEN command, to
+   which the channel number is assigned, you don't have to use a variable
+   in the other FILE commands if you know what the number is -- you can
+   just put the number. This saves you a few keystrokes when typing
+   commands at the prompt:
+
+  fopen \%c oofa.txt
+  flist
+  0. /usr/olga.oofa.txt (R) 0
+
+   This tells the channel number is 0 (the number on the left is the
+   channel file's channel number). Of course you can also find it by
+   echoing the variable:
+
+  echo \%c
+  0
+
+   Or with "fstatus \%c". Now you can type commands like:
+
+  fread 0
+
+   to read a line from the file. Obviously, however, using digits rather
+   than a variable for the channel number would be poor practice in a
+   script.
+
+   If in commands like:
+
+  fread \%c \%a
+
+   you have trouble remembering which variable is which, note that the
+   channel number is, indeed, a number. Anywhere C-Kermit accepts a
+   number it can also accept an expression, so you can put parentheses
+   around the channel number to remind you it's the channel number and
+   not the variable into which data is to be read:
+
+  fread (\%c) \%a
+
+   Normally channel numbers are assigned sequentially as 0, 1, 2, ... up
+   to the limit. However, once you start closing files, there can be
+   holes in the sequence. New channels are assigned to fill in the holes.
+   Thus you can't depend on channel numbers being in any particular
+   sequence.
+     _________________________________________________________________
+
+    1.22.5. FILE Command Errors
+
+   Each FILE command sets the variable \v(f_error) to one of the
+   following values:
+
+    0 = No error
+   -1 = System error
+   -2 = Attempt to read after end of file
+   -3 = Channel not open
+   -4 = Channel number out of range (negative or too large)
+   -5 = Numeric argument (size, ...) out of range
+   -6 = File not found
+   -7 = Bad or missing filename
+   -8 = Too many files are already open (FILE OPEN only)
+   -9 = Forbidden operation (e.g. write to a read-only file)
+  -10 = Access denied
+  -11 = Illegal combination of OPEN modes (FILE OPEN only)
+  -12 = Buffer overflow
+  -13 = Current line number unknown (for relative line seeks)
+  -14 through -98: Reserved.
+  -99 = Requested operation not implemented in this version of C-Kermit
+ -999 = Unknown error
+
+   When \v(f_error) is -1, this means the FILE command failed because
+   because of a system error, in which case you can examine the following
+   variables:
+
+  \v(errno)     = System error number.
+  \v(errstring) = Error message corresponding to \v(errno).
+
+   A special function is available for translating the \v(f_error) code
+   to an error message string:
+
+\f_errmsg([code])
+  If the code is -1, returns error message of the most recent system
+  error; otherwise if the code is a valid \v(f_error) value, the associated
+  message is returned.  If the code is omitted, the status message
+  corresponding to the current \v(f_error) value is returned.
+
+   A FILE command that fails prints the appropriate error message
+   automatically, except when the command is READ or SEEK and the error
+   is -2 (end of file); in that case, the command still fails, but does
+   not print a message. This allows constructions such as:
+
+  fopen \%c oofa.txt
+  while success { fread \%c }
+  fclose \%c
+
+   to work as expected, i.e. without an annoying message when the end of
+   file is reached.
+     _________________________________________________________________
+
+    1.22.6. File I/O Variables
+
+   The variables associated with the file i/o package are:
+
+   \v(f_count)
+          Result of the most recent FILE COUNT (FCOUNT) command.
+
+   \v(f_error)
+          Numeric error code of most recent FILE command (0 = no error).
+
+   \v(f_max)
+          Maximum number of files open simultaneously.
+     _________________________________________________________________
+
+    1.22.7. File I/O Functions
+
+   Some of the FILE commands can also be issued as function calls, which
+   makes script writing a bit more convenient, especially for C
+   programmers. Also, several functions are provided that do not have
+   command equivalents. Each of these functions takes a channel number as
+   the first argument. These functions do not work for OPEN { READ,
+   !READ, WRITE, !WRITE, and APPEND } files.
+
+   \f_status(channel)
+          Returns 0 if the channel is not open, otherwise a number
+          between 1 and 15 which is the sum of the OPEN modes:
+
+  1 = /READ
+  2 = /WRITE
+  4 = /APPEND
+  8 = /BINARY
+
+   The remaining functions work only for open channels. Each of these
+   functions can fail for the applicable reasons listed in [379]Section
+   1.22.5. For instructions on handling function errors, see [380]Section
+   7.12.
+
+   \f_pos(channel)
+          Returns the file's current read/write pointer (0-based). There
+          is no FILE command equivalent.
+
+   \f_line(channel)
+          Returns the file's current line number (0-based), if known,
+          otherwise -1. There is no FILE command equivalent. The line
+          number is known as long as no character or block i/o has been
+          done on the channel.
+
+   \f_handle(channel)
+          Returns the "file handle" of the file. That is, it translates
+          the portable C-Kermit channel number into a system-specific
+          file handle or number that can be passed to other programs on
+          the same platform. In UNIX this is a file descriptor. There is
+          no FILE command equivalent.
+
+   \f_eof(channel)
+          Returns 1 if the read/write pointer of the file on the given
+          channel is at the end of the file, 0 otherwise. Convenient in
+          WHILE statements, e.g.:
+
+    while not \f_eof(\%c) { fread \%c }
+
+   \f_getchar(channel)
+          Equivalent to FREAD /CHAR. Returns the character actually read.
+          If \f_getchar() does not fail but the return value is empty,
+          this means a NULL character was read.
+
+   \f_getline(channel)
+          Equivalent to FREAD /LINE. Returns the line actually read, but
+          with the line terminator stripped. If \f_getline() does not
+          fail but the return value is empty, this normally means an
+          empty line was read.
+
+   \f_getblock(channel,n)
+          Equivalent to FREAD /SIZE:n. Returns the block of characters
+          actually read. If the returned block is smaller than n, it
+          indicates either that the end of file was reached or a NUL
+          character is in the block.
+
+   \f_putchar(channel,c)
+          Equivalent to FWRITE /CHARACTER. Writes the character c. If c
+          contains more than one character, only the first is written. If
+          c is empty a NUL is written. Returns the number of characters
+          written on success, or a negative error code upon failure.
+
+   \f_putline(channel,string)
+          Equivalent to FWRITE /LINE. Writes the string and adds the
+          appropriate line termination character or sequence. If the
+          string is empty or omitted, an empty line is written. Returns
+          the number of characters written on success, or a negative
+          error code upon failure.
+
+   \f_putblock(channel,string)
+          Equivalent to FWRITE /STRING. Writes the string as given. If
+          the string is empty or omitted, nothing is written. Returns the
+          number of characters written on success, or a negative error
+          code upon failure.
+     _________________________________________________________________
+
+    1.22.8. File I/O Function Examples
+
+  fopen /read \%c oofa.txt            ; Open our favorite file for reading
+  if failure exit 1                   ; Check that it's open
+  while not \f_eof(\%c) {             ; Loop until EOF
+      .line := \f_getline(\%c)        ; Get a line
+      if success echo {\m(line)}      ; Echo it
+  }
+  if not \f_eof(\%c) {                ; Check reason for loop exit
+      exit 1 File Error: \f_errmsg()  ; If not EOF say so.
+  }
+
+  frewind \%c                         ; Rewind the file
+  while not \f_eof(\%c) {             ; Same thing but with block i/o
+      .block := \f_getblock(\%c,256)  ; (much faster than line i/o)
+      if success xecho {\m(block)}
+  }
+
+  frewind \%c                         ; Rewind again
+  while not \f_eof(\%c) {             ; Same deal but with character i/o
+      .c := \f_getchar(\%c)           ; (much slower than line i/o)
+      if success xecho {\m(c)}
+  }
+  close \%c
+
+   To close all open files (equivalent to FCLOSE ALL):
+
+  for \%i 0 \v(f_max)-1 1 {
+      if \f_status(\%i) fclose \%i
+  }
+     _________________________________________________________________
+
+  1.23. The EXEC Command
+
+   The EXEC command is available only in UNIX.
+
+   EXEC [ /REDIRECT ] command [ arg1 [ arg2 [ ... ] ]
+          Runs the given command with the arguments in such a way that
+          the command replaces C-Kermit in memory, and C-Kermit ceases to
+          execute. EXEC is like RUN, except instead of returning to
+          C-Kermit when finished, the command returns to whatever process
+          invoked Kermit.
+
+   In the normal case, no files are closed, so the EXEC'd command
+   inherits the open files, read/write pointers, working directory,
+   process ID, user ID (unless command is SUID), group ID (unless command
+   is SGID), groups, etc. (In UNIX, the EXEC command is simply a front
+   end for execvp().)
+
+   If the /REDIRECT switch is included, then if a connection is open (SET
+   LINE or SET HOST), it becomes the standard input and output of the
+   EXEC'd program. If no connection is open, the /REDIRECT switch has no
+   effect. For example to use C-Kermit for PPP dialing in Linux:
+
+  set modem type usr          ; Specify the kind of modem you have
+  set line /dev/ttyS1         ; Specify the device it's connected to
+  set speed 57600             ; and the speed
+  set flow rts/cts            ; and flow control.
+  set dial retries 100        ; Try the dial sequence up to 100 times.
+  dial {{9-212-555-1212}{9-212-555-1213}{9-212-555-1214}{9-212-555-1215}}
+  if fail exit 1
+  for \%i 1 16 1 {            ; Try up to 16 times to get login prompt
+      input 10 Login:         ; Wait 10 sec for it to appear
+      if success break        ; Got it - proceed...
+      output \13              ; Send a carriage return and try again
+  }
+  if ( > \%i 16 ) stop 1 NO LOGIN PROMPT
+  lineout \(myuserid)         ; Send user ID
+  input 30 assword:           ; Wait for Password prompt
+  if fail stop 1 NO PASSWORD PROMPT
+  lineout \m(mypassword)      ; Send the password.
+  exec /redirect pppd         ; Replace ourselves with pppd.
+
+   In this example we assume that the script has already set up the
+   myuserid and mypassword variables -- normally the password should be
+   prompted for, rather than stored on disk. Notice the advantages over
+   the well-known "chat script":
+     * You don't have to control the modem itself with AT commands;
+       Kermit's DIAL command does this for you.
+     * You can have Kermit automatically redial as many times as you want
+       until it gets a connection (if this is legal in your country).
+     * You can have Kermit fetch the number or numbers from a dialing
+       directory.
+     * You can have Kermit cycle through a list of phone numbers (this is
+       new in C-Kermit 7.0; see [381]Section 2.1.16) without having to
+       enter the numbers in a dialing directory.
+     * Dialing is location-independent; you can use the same script to
+       dial from different areas or countries.
+     * Once the connection is made, the full power of Kermit's script
+       language is available to manage the dialog with the terminal
+       server or other device that answers the phone call.
+
+   NOTE: PPP and SLIP dialing are not available in Windows 95/98/NT/2000,
+   whose APIs do not provide a method for an application to hand over a
+   connection to the PPP or SLIP driver.
+     _________________________________________________________________
+
+  1.24. Getting Keyword Lists with '?'
+
+   Suppose you type "te" at the C-Kermit> 6.0 prompt and then Esc or Tab
+   to request keyword completion. Kermit beeps, indicating that more than
+   one command starts with "te". But if you type '?' to see what they
+   are, Kermit shows only "telnet". So why the beep? Because of invisible
+   keywords like "telopt", "terminal", and "text". Lots of keywords are
+   invisible because they are either synonyms for other keywords or else
+   esoteric options to be used only in special circumstances, so we don't
+   want them cluttering up the menus.
+
+   But then there is no way for you to discover them. So in C-Kermit 7.0,
+   if you type '?' AFTER the beginning of a keyword field, then invisible
+   keywords are shown too:
+
+  C-Kermit> te<Esc><BEEP>
+  C-Kermit> te? Command, one of the following:
+   telnet    telopt    terminal  text
+  C-Kermit>te
+
+   But if '?' is typed at the beginning of a field, only visible keywords
+   are shown, as before (so, in this example, if '?' is typed at the
+   C-Kermit> prompt, "telnet" is the only command shown that starts with
+   "te").
+     _________________________________________________________________
+
+  2. MAKING AND USING CONNECTIONS The SET LINE, SET HOST, and SET PORT (a
+  synonym for SET LINE) commands have new synonyms, in which the word SET is
+  replaced by the word OPEN: OPEN LINE, etc. There is no new functionality
+  here, but OPEN is a better verb, since SET generally takes no action, whereas
+  these commands actually try to open a connection. Furthermore, there is the
+  symmetry with CLOSE.
+    ________________________________________________________________________
+
+  2.0. SET LINE and SET HOST Command SwitchesThe SET LINE (SET PORT) and SET
+  HOST commands now allow switches before the device or host name, in most
+  cases, and under certain circumstances, also at the end. The new syntax is
+  backwards compatible with the previous syntax; thus SET LINE, SET PORT, and
+  SET HOST commands in command files written for C-Kermit 6.0 or earlier still
+  work. The expanded syntax is:
+
+  { OPEN, SET } { LINE, PORT, HOST } [ switches ] device-or-address [ switches
+  ]
+
+  The first group of switches is:
+
+   /NETWORK-TYPE:{TCP/IP,X.25,PIPE,PTY...}
+          When more than one network type is available, this lets you
+          specify the type of network to use for this connection without
+          affecting your global SET NETWORK TYPE. See [382]Section 2.7
+          about pipes and ptys.
+
+   /USERID:[string]
+          This switch is equivalent to SET LOGIN USERID. If a string is
+          given, it sent to host during Telnet negotiations; if this
+          switch is given but the string is omitted, no user ID is sent
+          to the host. If this switch is not given, your current LOGIN
+          USERID (\v(userid) value), if any, is sent. Unlike most other
+          switches, this one is "sticky", since the value must persist
+          throughout the session in case the server requests the ID
+          string at a later time.
+
+   /CONNECT
+          Enter CONNECT mode immediately and automatically after the
+          device or connection is open. On serial devices, however, when
+          CARRIER-WATCH is not OFF, wait up to 1 second for the Carrier
+          Detect signal to appear before trying to connect, to give the
+          device time to react DTR, which might have been off prior to
+          opening the device.
+
+   /SERVER
+          Enter server mode immediately and automatically after the
+          device or connection is open. Treatment of carrier is the same
+          as for /CONNECT.
+
+   /WAIT
+   /NOWAIT
+          For Telnet connections only: Like SET TELNET WAIT { ON, OFF },
+          but applies only to this connection, and in fact applies only
+          when OPENing this connection (which is usually the only place
+          it matters). Typically you would use TELNET /NOWAIT to make a
+          connection to a misbehaving Telnet server that does not reply
+          to negotiations as required by the Telnet protocol definition.
+
+   Note: /CONNECT and /SERVER switches are not available in the RLOGIN
+   and TELNET commands, since these commands already include an implicit
+   /CONNECT and preclude automatic entry into server mode.
+
+   The /CONNECT and /SERVER switches are especially useful with "set host
+   *" connections. For example, suppose you want to start a Kermit server
+   on socket 3000 of your TCP host. Normally you would have to give the
+   command:
+
+  set host * 3000
+
+   and then wait for a connection to come in, and only then could you
+   give the SERVER command (or else define a macro to do this, and then
+   execute the macro). Now you can do it in one step:
+
+  set host /server * 3000
+
+   This tells C-Kermit to wait for the connection and then enter server
+   mode once it comes in, no matter how long it takes. Similarly, "set
+   host /conn *" can be used to wait for a "chat" connection to come in.
+
+   Another set of switches is available in VMS only, for use only with
+   SET LINE:
+
+   /SHARE
+          Allows the SET LINE device to be opened in shared mode.
+          Normally it makes no sense to open a serial device in shared
+          mode, but it's necessary when C-Kermit is running in an
+          environment such as DECIntact, that opens your job's
+          controlling terminal in such a way that C-Kermit can't open it
+          too, unless it enables SHARE privilege. Note: SHARE privilege
+          is required.
+
+   /NOSHARE
+          Requires that the SET LINE device not be in use by any other
+          process in order for it to be successfully opened by C-Kermit.
+          If neither /SHARE nor /NOSHARE is specified, /NOSHARE is used.
+
+   The second group of switches is:
+
+   /NO-TELNET-INIT
+          Do not send initial Telnet negotiations even if this is a
+          Telnet port.
+
+   /RAW-SOCKET
+          This is a connection to a raw TCP socket ([383]Section 2.3.5).
+
+   /RLOGIN
+          Use Rlogin protocol even if this is not an Rlogin port.
+
+   /TELNET
+          Send initial Telnet negotiations even if this is not a Telnet
+          port.
+
+   As of C-Kermit 7.0 and K95 1.1.19, the TELNET command includes an
+   implicit /TELNET switch. So if you TELNET to a non-TELNET port, Kermit
+   sends initial Telnet negotiations. This makes sense, since that's what
+   "telnet" means.
+
+   If you want to make a connection to a non-Telnet port without sending
+   initial Telnet negotiations, use:
+
+  set host [ /connect ] name-or-address port
+
+   or:
+
+  telnet name-or-address port /no-telnet-init
+
+   Additional switches might be added in the future; type "set host ?" or
+   "set line ?" to see a current list.
+     _________________________________________________________________
+
+  2.1. Dialing
+
+   Automatic redialing is illegal or restricted in many countries, so
+   until C-Kermit 7.0, it was disabled by default, i.e. until a SET DIAL
+   RETRIES command was given. In C-Kermit 7.0, if no SET DIAL RETRIES
+   command has been given, a default is picked dynamically at DIAL time
+   based on the calling country code, if known. At this writing, the only
+   country code known to have no restrictions on automatic redialing is
+   1. So in this case a limit of 10 is chosen; otherwise 1. If you have
+   not given an explicit SET DIAL RETRIES command, SHOW DIAL shows the
+   value as "(auto)", and then the value actually used is shown when you
+   give the DIAL command.
+
+   As of C-Kermit 7.0, automatic redialing is automatically canceled if
+   the call could not be placed because no dialtone was detected.
+     _________________________________________________________________
+
+    2.1.1. The Dial Result Message
+
+   If DIAL DISPLAY is not ON, the "Call complete" message now shows the
+   modem's call result message, for example:
+
+  Dialing: ...
+  Call complete: "CONNECT 31200/ARQ/V32/LAPM/V42BIS"
+
+   The exact format and contents of this message, of course, depends on
+   the make, model, and configuration of your modem, so use your modem
+   manual to interpret it. The call result message is also available in
+   C-Kermit's \v(dialresult) variable.
+
+  C-Kermit> echo \v(dialresult)
+  CONNECT 31200/ARQ/V32/LAPM/V42BIS
+  C-Kermit> echo Speed = \fword(\v(dialresult),2)
+  Speed = 31200
+  C-Kermit>
+
+   Suppose your modem reports the modulation speed as shown above and you
+   want to ensure your call is completed at (say) 24000 bps or more. You
+   can use a little macro to do the job:
+
+define HSDIAL {                ; High Speed DIAL
+    local \%s
+    if < \v(argc) 1 if not def \v(dialnumber) end 1 Usage: \%0 number
+    set dial retries 100
+    set dial interval 1
+    while true {
+        dial \%*
+        if fail end 1 DIAL failed.
+        asg \%s \fword(\v(dialresult),2)
+        if def \%s if numeric \%s if not < \%s 24000 break
+    }
+}
+
+   (See [384]Section 7.5 about the \%* variable.)
+     _________________________________________________________________
+
+    2.1.2. Long-Distance Dialing Changes
+
+   Due to the glut of cell phones, pagers, fax machines, ISPs, etc, area
+   codes and dialing rules are changing all the time. In the North
+   American Numbering Plan (NANP) countries (USA, Canada, etc), area
+   codes are split or overlayed with increasing frequency, and 10- and
+   11-digit dialing is gradually becoming the norm for local calls.
+   Changes are occurring In Europe, too, partly for these reasons and
+   partly because of some new EC rules.
+
+   In France, effective 18 October 1996, all calls, even local ones, must
+   be dialed with an area code. French area codes are presently 1-digit
+   numbers, 1-6, and the long-distance dialing prefix is 0. All calls
+   within France are considered long distance and begin with 01, 02, ...,
+   06.
+
+   Effective 1 May 1997, all calls within the US state of Maryland, even
+   local ones, must be dialed with an area code but without the
+   long-distance prefix -- this is the now widely-known North American
+   phenomenon of "ten digit dialing". The same is happening elsewhere --
+   many cities in Florida adopted 10-digit dialing in 1998.
+
+   In Italy beginning 19 June 1998, all calls to fixed (as opposed to
+   mobile) numbers must be prefixed by 0. When calling into Italy from
+   outside, the 0 must follow the country code (39). Calls to cell
+   phones, however, must be placed without the 0. Then on 29 December
+   2000, the 0 will become a 4 (for calling fixed numbers) and a prefix
+   of 3 must used for calling mobile phones. More info at:
+   http://www.telecomitalia.it/npnn/.
+
+   In Spain, effective 4 April 1998, with hard cutover on 18 July 1998,
+   all calls within the country must be dialed with 9 digits, and all
+   calls from outside Spain must also be dialed with 9 digits (after the
+   country code, 34). The new 9-digit numbers all begin with "9". More
+   info at: [385]http://www.telefonica.es/cambiodenumeracion/
+
+   Several new dialing features and commands have been added in version
+   6.1 and 7.0 to address these changes.
+
+   C-Kermit 6.0 and Kermit 95 1.1.11 and earlier handle the French
+   situation via a reasonable subterfuge (setting the local area code to
+   a nonexistent one), but did not handle "ten-digit dialing" well at
+   all; the recommended technique was to change the long-distance dialing
+   prefix to nothing, but this defeated Kermit's "list numbers for one
+   name" feature when the numbers were in different locations. For
+   example:
+
+  set dial ld-prefix
+  dial onlineservice
+
+   where "onlineservice" is a dialing directory entry name corresponding
+   to entries that are in (say) Maryland as well as other states, would
+   not correctly dial the numbers not in Maryland.
+
+   A new command lets you specify a list of area codes to be considered
+   local, except that the area code must be dialed:
+
+   SET DIAL LC-AREA-CODES [ areacode [ areacode [ areacode [ ... ] ] ] ]
+          The list may include up to 32 area codes. If a number is called
+          whose area code is in this list, it is dialed WITHOUT the
+          long-distance prefix, but WITH the area code.
+
+   So in Maryland, which (last time we looked) has two area codes, 410
+   and 301, the setup would be:
+
+  SET DIAL LC-AREA-CODES 410 301
+
+   Example:
+
+  SET DIAL LD-PREFIX 1
+  SET DIAL AREA-CODE 301
+  SET DIAL LC-AREA-CODES 410 301 <-- Area codes in 10-digit dialing region
+  DIAL +1 (301) 765-4321         <-- Dials 3017654321  (local with area code)
+  DIAL +1 (410) 765-4321         <-- Dials 4107654321  (local with area code)
+  DIAL +1 (212) 765-4321         <-- Dials 12127654321 (long distance)
+
+   The SET DIAL LC-AREA-CODES command does not replace the SET DIAL
+   AREA-CODE command. The latter specifies the area code you are dialing
+   from. If the called number is in the same area code, then the area
+   code is dialed if it is also in the LC-AREA-CODES list, and it is not
+   dialed otherwise. So if "301" had not appeared in the LC-AREA-CODES
+   list in the previous example:
+
+  SET DIAL LD-PREFIX 1
+  SET DIAL AREA-CODE 301
+  SET DIAL LC-AREA-CODES 410     <-- Area codes in 10-digit dialing region
+  DIAL +1 (301) 765-4321         <-- Dials 7654321     (local)
+  DIAL +1 (410) 765-4321         <-- Dials 4107654321  (local with area code)
+  DIAL +1 (212) 765-4321         <-- Dials 12127654321 (long distance)
+
+   The new Kermit versions also add a Local Call Prefix and Local Call
+   Suffix, in case you have any need for it. These are added to the
+   beginning and of local phone numbers (i.e. numbers that are not
+   long-distance or international). Examples:
+
+  SET DIAL LD-PREFIX 1
+  SET DIAL LC-PREFIX 9
+  SET DIAL LC-SUFFIX *
+  SET DIAL LC-AREA-CODES 410     <-- Area codes in 10-digit dialing region
+  SET DIAL AREA-CODE 301
+  DIAL +1 (301) 765-4321         <-- Dials 97654321*     (local)
+  DIAL +1 (410) 765-4321         <-- Dials 94107654321*  (local with area code)
+  DIAL +1 (212) 765-4321         <-- Dials 12127654321   (long distance)
+     _________________________________________________________________
+
+    2.1.3. Forcing Long-Distance Dialing
+
+   Suppose a number is in your country and area, but for some reason you
+   need to dial it long-distance anyway (as is always the case in
+   France). There have always been various ways to handle this:
+
+    1. Temporarily set your area code to a different (or nonexistent or
+       impossible) one (but this required knowledge of which area codes
+       were nonexistent or impossible in each country).
+    2. Dial the number literally instead of using the portable format,
+       but this defeats the purpose of the portable dialing directory.
+
+   Now there is also a new command that, very simply, can force
+   long-distance dialing:
+
+   SET DIAL FORCE-LONG-DISTANCE { ON, OFF }
+          If a call is placed to a portable phone number within the same
+          country code as the calling number, it is dialed with the
+          long-distance prefix and the area code if FORCE-LONG-DISTANCE
+          is ON. If OFF, the regular rules and procedures apply.
+
+   Example (France):
+
+  SET DIAL COUNTRY-CODE 33
+  SET DIAL AREA-CODE 6
+  SET DIAL FORCE-LONG-DISTANCE ON
+
+   (In fact, SET DIAL COUNTRY-CODE 33 automatically sets DIAL
+   FORCE-LONG-DISTANCE ON...)
+
+   Example (USA, for a certain type of reverse-charge calling in which
+   the called number must always be fully specified):
+
+  SET DIAL PREFIX 18002666328$     ; 1-800-COLLECT
+  SET DIAL COUNTRY-CODE 1
+  SET DIAL AREA-CODE 212
+  SET DIAL FORCE-LONG-DISTANCE ON
+
+   Example (Toronto, where calls to exchange 976 within area code 416
+   must be dialed as long distance, even when you are dialing from area
+   code 416):
+
+  SET DIAL COUNTRY-CODE 1
+  SET DIAL AREA-CODE 416
+  SET DIAL FORCE-LONG-DISTANCE ON
+  DIAL +1 (416) 976-xxxx
+
+   If dialing methods were consistent and sensible, of course it would be
+   possible to always dial every domestic call as if it were long
+   distance. But in many locations this doesn't work or if it does, it
+   costs extra. The following macro can be used for dialing any given
+   number with forced long-distance format:
+
+  define LDIAL {
+      local \%x
+      set dial force-long-distance on
+      dial \%*
+      asg \%x \v(success)
+      set dial force-long-distance off
+      end \%x
+  }
+
+   (See [386]Section 7.5 about the \%* variable.)
+     _________________________________________________________________
+
+    2.1.4. Exchange-Specific Dialing Decisions
+
+   This applies mainly to the North American Numbering Plan (NANP). Refer
+   to the section "Alternative notations" in [387]Using C-Kermit 2nd
+   Edition, pages 106-107, and the story about Toronto on page 110. Using
+   the new LC-AREA-CODES list, we can address the problem by treating the
+   exchange as part of the area code:
+
+  SET DIAL LD-PREFIX 1
+  SET DIAL AREA-CODE 416
+  SET DIAL LC-AREA-CODES 905276
+  DIAL +1 416 765 4321               <-- 7654321      (local)
+  DIAL +1 905 276 4321               <-- 9052764321   (local with area code)
+  DIAL +1 905 528 4321               <-- 19055284321  (long distance)
+
+   The same technique can be used in Massachusetts (story at top of page
+   111) and in any other place where dialing to some exchanges within a
+   particular area code is local, but to others in the same area code is
+   long distance.
+     _________________________________________________________________
+
+    2.1.5. Cautions about Cheapest-First Dialing
+
+   Kermit does not maintain a knowledge base of telephony information; it
+   only provides the tools to let you enter a phone number in a standard
+   format and dial it correctly from any location in most cases.
+
+   In particular, Kermit does not differentiate the charging method from
+   the dialing method. If a call that is DIALED as long-distance (e.g.
+   from 212 to 718 in country code 1) is not CHARGED as long distance, we
+   have no way of knowing that without keeping a matrix of charging
+   information for every area-code combination within every country, and
+   any such matrix would be obsolete five minutes after it was
+   constructed. Thus, "cheapest-first" sorting is only as reliable as our
+   assumption that the charging method follows the dialing method. A good
+   illustration would be certain online services that have toll-free
+   dialup numbers which they charge you a premium (in your online service
+   bill) for using.
+     _________________________________________________________________
+
+    2.1.6. Blind Dialing (Dialing with No Dialtone)
+
+   C-Kermit's init string for Hayes-like modems generally includes an X4
+   command to enable as many result codes as possible, so that Kermit can
+   react appropriately to different failure reasons. One of the result
+   codes that X4 enables is "NO DIALTONE". A perhaps not obvious side
+   effect of enabling this result code that the modem must hear dialtone
+   before it will dial.
+
+   It is becoming increasingly necessary to force a modem to dial even
+   though it does not hear a dialtone on the phone line; for example,
+   with PBXs that have strange dialtones, or with phone systems in
+   different countries, or with ISDN phones, etc. This is called "blind
+   dialing".
+
+   C-Kermit 7.0 has two new commands to cope with this situation:
+
+   SET DIAL IGNORE-DIALTONE { ON, OFF }
+          OFF (the default) means to tell the modem to wait for dialtone
+          before dialing. ON means to enable "blind dialing", i.e. tell
+          the modem NOT to wait for dialtone before dialing. Generally
+          this is accomplished by sending ATX3 to the modem just prior to
+          dialing. SET MODEM TYPE xxx and then SHOW MODEM displays
+          Kermit's built-in "ignore dialtone" command.
+
+   SET DIAL COMMAND IGNORE-DIALTONE text
+          This lets you change the built-in ignore-dialtone command (such
+          as ATX3) to whatever you choose, in case the built-in one does
+          not work, or another command works better.
+
+   Notes:
+    1. The ignore-dialtone command is not sent unless SET DIAL
+       IGNORE-DIALTONE is ON.
+    2. The ATX3 command generally disables not only NO DIALTONE, but also
+       BUSY. So this will prevent Kermit from detecting when the line is
+       busy. This is a property of the modem, not of Kermit.
+     _________________________________________________________________
+
+    2.1.7. Trimming the Dialing Dialog
+
+   The command:
+
+  SET MODEM COMMAND action [ command ]
+
+   is used to override Kermit's built-in modem commands for each action,
+   for each kind of modem in its internal database. If you include a
+   command, this is used instead of the built-in one. If you omit the
+   command, this restores the original built-in command.
+
+   If you want to omit the command altogether, so Kermit doesn't send the
+   command at all, or wait for a response, use:
+
+  SET MODEM COMMAND action {}
+
+   That is, specify a pair of empty braces as the command, for example:
+
+  SET MODEM COMMAND ERROR-CORRECTION ON {}
+     _________________________________________________________________
+
+    2.1.8. Controlling the Dialing Speed
+
+   The rate at which characters are sent to the modem during dialing is
+   normally controlled by the built-in modem database. You might want to
+   override this if Kermit seems to be dialing too slowly, or it is
+   sending characters to the modem faster than the modem handle them. A
+   new command was added for this in C-Kermit 7.0:
+
+   SET DIAL PACING number
+          Specifies the number of milliseconds (thousandths of seconds)
+          to pause between each character when sending commands to the
+          modem during DIAL or ANSWER command execution. 0 means no pause
+          at all, -1 (the default) or any other negative number means to
+          use the value from the database. Any number greater than 0 is
+          the number of milliseconds to pause.
+
+   HINT: You might also need to control the rate at which the modem
+   generates Touch Tones during dialing, for example when sending a
+   numeric page. There are two ways to do this. One way is to insert
+   pause characters into the dialing string. For modems that use the AT
+   command set, the pause character is comma (,) and causes a 2-second
+   pause. On most modems, you can use the S8 register to change the pause
+   interval caused by comma in the dialing string. The other way is to
+   set your modem's tone generation interval, if it has a command for
+   that. Most AT-command-set modems use S11 for this; the value is in
+   milliseconds. For example on USR modems:
+
+  ATS11=200
+
+   selects an interval of 200 milliseconds to separate each dialing tone.
+
+   Hint: To add S-Register settings or other commands to your dialing
+   procedure, use the new SET MODEM COMMAND PREDIAL-INIT command
+   ([388]Section 2.2.2).
+     _________________________________________________________________
+
+    2.1.9. Pretesting Phone Number Conversions
+
+   The LOOKUP command now accepts telephone numbers as well as
+   directory-entry names, for example:
+
+  LOOKUP +1 (212) 7654321
+
+   When given a phone number, LOOKUP prints the result of converting the
+   phone number for dialing under the current dialing rules. For example,
+   if my country code is 1 and my area code is 212, and I am dialing out
+   from a PBX whose outside-line prefix is "93,":
+
+  C-Kermit> lookup +1 (212) 7654321
+  +1 (212) 7654321 => 93,7654321
+  C-Kermit>
+
+   You can also use the \fdialconvert(phone-number) function
+   ([389]Section 2.1.11) to do this programmatically:
+
+  C-Kermit> echo "\fdialconvert(+1 (212) 7654321)"
+  "93,7654321"
+  C-Kermit>
+
+   So the new LOOKUP behaves as follows:
+
+   LOOKUP portable-format-phone-number
+          Displays how the number would actually be dialed Sets FAILURE
+          if there was a conversion error, otherwise SUCCESS.
+
+   LOOKUP literal-format-phone-number
+          Displays the same literal-format-phone-number Always sets
+          SUCCESS.
+
+   LOOKUP dialing-directory-name
+          Displays all matching entries and converts portable phone
+          numbers. Sets SUCCESS if at least one entry was found,
+          otherwise FAILURE.
+
+   LOOKUP =anything
+          Displays "=anything" and sets SUCCESS.
+
+   There is, at present, no programmatic way to fetch numbers from the
+   dialing directory. This will be considered for a future release.
+     _________________________________________________________________
+
+    2.1.10. Greater Control over Partial Dialing
+
+   The following rules now apply to partial dialing:
+
+     * Phone number transformations based on country and area code,
+       application of prefixes, etc, are performed only on the first
+       PDIAL.
+     * Each PDIAL argument is looked up in the dialing directory, so it
+       is possible have directory entries for pieces of phone numbers or
+       other information.
+     * Suffixes are not applied automatically, since there is no way for
+       C-Kermit to know in which PDIAL segment you want them to be
+       applied.
+
+   However, the suffix that *would* have been applied, based on the
+   dialing rules that were invoked when processing the first PDIAL
+   command, is stored in the variable:
+
+  \v(dialsuffix)
+
+   which you can include in any subsequent PDIAL or DIAL commands.
+
+   Example:
+
+  pdial {\m(my_long_distance_pager_number_part_1)}
+  pdial {\m(my_long_distance_pager_number_part_2)}
+  pdial {\v(dialsuffix)}
+  pdial {\m(my_long_distance_pager_number_part_3)}
+  pdial {@\m(numeric_pager_code)#}
+     _________________________________________________________________
+
+    2.1.11. New DIAL-related Variables and Functions
+
+   \fdialconvert(s)
+          s is a phone number in either literal or portable format (not a
+          dialing directory entry name). The function returns the dial
+          string that would actually be used by the DIAL command when
+          dialing from the current location, after processing country
+          code, area code, and other SET DIAL values, and should be the
+          same as the result of LOOKUP when given a telephone number.
+
+   \v(dialsuffix)
+          Contains the suffix, if any, that was applied in the most
+          recent DIAL command, or the suffix that would have been applied
+          in the most recent PDIAL command. Use this variable to send the
+          dial suffix at any desired point in a PDIAL sequence.
+
+   \v(dialtype)
+          A number indicating the type of call that was most recently
+          placed. Can be used after a normal DIAL command, or after the
+          first PDIAL command in a PDIAL sequence. Values are:
+
+  -2: Unknown because TAPI handled the phone number translation.
+  -1: Unknown because some kind of error occured.
+   0: Internal within PBX.
+   1: Toll-free.
+   2: Local within calling area.
+   3: Unknown (e.g. because a literal-format phone number was given).
+   4: Long distance within country.
+   5: International
+
+   \v(dialcount)
+          The current value of the DIAL retry counter, for use in a DIAL
+          macro ([390]Section 2.1.13).
+
+   \v(d$px)
+          PBX Exchange (see [391]Section 2.1.12).
+
+   Other dial-related variables, already documented in [392]Using
+   C-Kermit (or other sections of this document, e.g. [393]Section
+   2.1.1), include \v(dialnumber), \v(dialstatus), etc. A convenient way
+   to display all of them is:
+
+  show variable dial  ; hint: abbreviate "sho var dial"
+
+   This shows the values of all the variables whose names start with
+   "dial". Also "show variable d$" (to show the \v(d$...) variables).
+     _________________________________________________________________
+
+    2.1.12. Increased Flexibility of PBX Dialing
+
+   Refer to [394]Using C-Kermit, 2nd Edition, pages 107-108. Recall that
+   three commands are needed to configure C-Kermit for dialing from a
+   PBX:
+
+  SET DIAL PBX-EXCHANGE number
+  SET DIAL PBX-INSIDE-PREFIX number
+  SET DIAL PBX-OUTSIDE-PREFIX number
+
+   Unfortunately, this model does not accommodate PBXs that have more
+   than one exchange. For example our PBX at Columbia University (which
+   must handle more than 10,000 phones) has 853-xxxx and 854-xxxx
+   exchanges.
+
+   Beginning in C-Kermit 7.0, the SET DIAL PBX-EXCHANGE command accepts a
+   list of exchanges, e.g.:
+
+  SET DIAL PBX-EXCHANGE 853 854
+
+   (multiple exchanges are separated by spaces, not commas).
+
+   So now when dialing a portable-format number that has the same country
+   and area codes as those of your dialing location, C-Kermit compares
+   the exchange of the dialed number with each number in the PBX Exchange
+   list (rather than with a single PBX Exchange number, as it did
+   formerly) to determine whether this is an internal PBX number or an
+   external call. If it is an external call, then the PBX Outside Prefix
+   is applied, and then the normal dialing rules for local or
+   long-distance calls.
+
+   If it is an inside call, the exchange is replaced by the PBX Inside
+   Prefix. But if the PBX has more than one exchange, a single fixed PBX
+   Inside Prefix is probably not sufficient. For example, at Columbia
+   University, we must dial 3-xxxx for an internal call to 853-xxxx, but
+   4-xxxx for a call to 854-xxxx. That is, the inside prefix is the final
+   digit of the exchange we are dialing. For this reason, C-Kermit 7.0
+   provides a method to determine the inside prefix dynamically at
+   dialing time, consisting of a new variable and new syntax for the SET
+   DIAL PBX-INSIDE-PREFIX command:
+
+   \v(d$px)
+          This variable contains the exchange that was matched when a PBX
+          internal call was detected. For example, if the PBX exchange
+          list is "853 854" and a call is placed to +1 (212) 854-9999,
+          \v(d$px) is set to 854.
+
+   SET DIAL PBX-INSIDE-PREFIX \fxxx(...)
+          If the PBX Inside Prefix is defined to be a function, its
+          evaluation is deferred until dialing time. Normally, this would
+          be a string function having \v(d$px) as an operand. Of course,
+          you can still specify a constant string, as before.
+
+   So given the following setup:
+
+  SET DIAL COUNTRY-CODE 1
+  SET DIAL AREA-CODE 212
+  SET DIAL PBX-OUTSIDE-PREFIX 93,
+  SET DIAL PBX-EXCHANGE 853 854
+  SET DIAL PBX-INSIDE-PREFIX \fright(\v(d$px),1)
+
+   The following numbers give the results indicated:
+
+ Number                   Result
+  +1 (212) 854-9876        4-9876
+  +1 (212) 853-1234        3-1234
+  +1 (212) 765-4321        93,765-4321
+  +1 (333) 765-4321        93,1333765-4321
+
+   Furthermore, the K_PBX_XCH environment variable may now be set to a
+   list of exchanges to automatically initialize C-Kermit's PBX exchange
+   list, for example (in UNIX ksh or bash):
+
+  export K_PBX_XCH="853 854"
+
+   (Quotes required because of the space.) Of course, this variable can
+   also be set to a single exchange, as before:
+
+  export K_PBX_XCH=853
+     _________________________________________________________________
+
+    2.1.13. The DIAL macro - Last-Minute Phone Number Conversions
+
+   After a DIAL or LOOKUP command is given, a list of phone numbers is
+   assembled from the dialing directory (if any), with all
+   location-dependent conversion rules applied as described in Chapter 5
+   of [395]Using C-Kermit.
+
+   However, additional conversions might still be required at the last
+   minute based on local or ephemeral conditions. So that you can have
+   the final word on the exact format of the dial string, C-Kermit 7.0
+   lets you pass the converted string through a macro of your own design
+   for final processing before dialing. The relevant command is:
+
+   SET DIAL MACRO [ name ]
+          Specifies the name of a macro to be run on each phone number
+          after all built-in conversions have been applied, just before
+          the number is dialed. If no name is given, no macro is run. The
+          phone number, as it would have been dialed if there were no
+          dial macro, is passed to the macro.
+
+   The dial macro can do anything at all (except start a file transfer).
+   However, the normal use for the macro would be to modify the phone
+   number. For this reason the phone number is passed to the macro as
+   argument number 1 (\%1). To cause a modified number to be dialed, the
+   macro should terminate with a RETURN statement specifying a return
+   value. To leave the number alone, the macro should simply end.
+   Example:
+
+  define xxx return 10108889999$\%1
+  set dial macro xxx
+  dial xyzcorp
+
+   This defines a DIAL MACRO called xxx, which puts an access code on the
+   front of the number. Another example might be:
+
+  def xxx if equal "\v(modem)" "hayes-1200" return \freplace(\%1,$,{,,,,,})
+  set dial macro xxx
+  dial xyzcorp
+
+   which replaces any dollar-sign in the dial string by a series of five
+   commas, e.g. because this particular modem does not support the "wait
+   for bong" feature (remember that commas that are to be included
+   literally in function arguments must be enclosed in braces to
+   distinguish them from the commas that separate the arguments) and when
+   the IF condition is not satisfied, the macro does not return a value,
+   and so the number is not modified. Then when a DIAL command is given
+   referencing a dialing directory entry, "xyzcorp". The macro is
+   automatically applied to each matching number.
+
+   Numerous dial-, modem-, communications-, and time-related variables
+   are available for decision making your dial macro. Type SHOW VARIABLES
+   for a list. Of particular interest is the \v(dialcount) variable,
+   which tells how many times the DIAL command gone through its retry
+   loop: 1 on the first try, 2 on the second, 3 on the third, and so on,
+   and the \v(dialresult) and \v(dialstatus) variables.
+
+   Here are some other applications for the DIAL MACRO (from users):
+
+     * Phone numbers in the dialing directory are formatted with '-' for
+       readability, but some modems don't like the hyphens, so the DIAL
+       macro is used to remove them before dialing; e.g
+       0090-123-456-78-99 becomes 00901234567899: "def xxx return
+       \freplace(\%1,-)".
+     * To set some specific modem (or other) options depending on the
+       called customer or telephone number.
+     * Choosing the most appropriate provider based on (e.g.) time of
+       day, or cycling through a list of providers in case some providers
+       might be busy.
+
+   To illustrate the final item, suppose you have a choice among many
+   phone service providers; the provider is chosen by dialing an access
+   code before the number. Different providers might be better (e.g.
+   cheaper) for certain times of day or days of the week, or for dialing
+   certain locations; you can use the DIAL macro to add the access for
+   the most desirable provider.
+
+   Similarly, when the same number might be reached through multiple
+   providers, it's possible that one provider might not be able to
+   complete the call, but another one can. In that case, you can use the
+   DIAL macro to switch providers each time through the DIAL loop --
+   that's where the \v(dialcount) variable comes in handy.
+
+   The following command can be used to debug the DIAL macro:
+
+   SET DIAL TEST { ON, OFF }
+          Normally OFF, so the DIAL command actually dials. When ON, the
+          DIAL command performs all lookups and number conversions, and
+          then goes through the number list and retry loop, but instead
+          of actually dialing, lists the numbers it would have called if
+          none of the DIAL attempts succeeded (or more precisely, every
+          number was always busy).
+     _________________________________________________________________
+
+    2.1.14. Automatic Tone/Pulse Dialing Selection
+
+   SET DIAL METHOD { AUTO, DEFAULT, PULSE, TONE }
+          Chooses the dialing method for subsequent calls.
+
+   Prior to version 7.0, C-Kermit's DIAL METHOD was DEFAULT by default,
+   meaning it does not specify a dialing method to the modem, but relies
+   on the modem to have an appropriate default dialing method set. So,
+   for example, when using Hayes compatible modems, the dial string would
+   be something like ATD7654321, rather than ATDT7654321 or ATDP7654321.
+
+   In C-Kermit 7.0 and K95 1.1.19, the dial method can be set from the
+   environment variable:
+
+  K_DIAL_METHOD
+
+   when Kermit starts. The values can be TONE, PULSE, or DEFAULT, e.g.
+   (UNIX):
+
+  set K_DIAL_METHOD=TONE; export K_DIAL_METHOD
+
+   In the absence of a K_DIAL_METHOD definition, the new default SET DIAL
+   METHOD is AUTO rather than DEFAULT. When DIAL METHOD is AUTO and the
+   local country code is known, then if tone dialing is universally
+   available in the corresponding area, tone dialing is used; if dialing
+   from a location where pulse dialing is mandatory, pulse dialing is
+   used.
+
+   The "tone country" and "pulse country" lists are preloaded according
+   to our knowledge at the time of release. You can see their contents in
+   the SHOW DIAL listing. You can change the lists with:
+
+   SET DIAL TONE-COUNTRIES [ cc [ cc [ ... ] ] ]
+          Replaces the current TONE-COUNTRIES list with the one given.
+          Each cc is a country code; separate them with spaces (not
+          commas). Example:
+
+  set dial tone-countries 1 358 44 46 49
+
+          If no country codes are given, the current list, if any, is
+          removed, in which case SET DIAL METHOD AUTO is equivalent to
+          SET DIAL METHOD DEFAULT.
+
+   SET DIAL PULSE-COUNTRIES [ cc [ cc [ ... ] ] ]
+          Replaces the current PULSE-COUNTRIES list with the one give.
+          Syntax and operation is like SET DIAL TONE-COUNTRIES.
+
+   If the same country code appears in both lists, Pulse takes
+   precedence.
+
+   The SET DIAL TONE- and PULSE-COUNTRIES commands perform no
+   verification whatsoever on the cc's, since almost any syntax might be
+   legal in some settings. Furthermore, there is no facility to edit the
+   lists; you can only replace the whole list. However, since the only
+   purpose of these lists is to establish a basis for picking tone or
+   pulse dialing automatically, all you need to override the effect of
+   the list is to set a specific dialing method with SET DIAL METHOD TONE
+   or SET DIAL METHOD PULSE.
+     _________________________________________________________________
+
+    2.1.15. Dial-Modifier Variables
+
+   As of C-Kermit 7.0, dial modifiers are available in the following
+   variables:
+
+ \v(dm_lp) Long pause
+ \v(dm_sp) Short pause
+ \v(dm_pd) Pulse dial
+ \v(dm_td) Tone dial
+ \v(dm_wa) Wait for answer
+ \v(dm_wd) Wait for dialtone
+ \v(dm_rc) Return to command mode
+
+   You can use these in your dial strings in place of hardwired modifiers
+   like "@", ",", etc, for increased portability of scripts. Example:
+
+  C-Kermit>set modem type usrobotics
+  C-Kermit>sho variables dm
+   \v(dm_lp) = ,
+   \v(dm_sp) = /
+   \v(dm_pd) = P
+   \v(dm_td) = T
+   \v(dm_wa) = @
+   \v(dm_wd) = W
+   \v(dm_rc) = ;
+  C-Kermit>exit
+     _________________________________________________________________
+
+    2.1.16. Giving Multiple Numbers to the DIAL Command
+
+   Prior to C-Kermit 7.0, the only way to give a DIAL command a list of
+   phone numbers to try until one answers was to create a dialing
+   directory that had multiple entries under the same name, and then use
+   that entry name in the DIAL command. Now a list of numbers can be
+   given to the DIAL command directly in the following format:
+
+  dial {{number1}{number2}{number3}...}
+
+   This is the same list format used by SEND /EXCEPT: and other commands
+   that allow a list where normally a single item is given. Restrictions
+   on this form of the DIAL command are:
+
+     * The first two braces must be adjacent; spacing is optional
+       thereafter.
+     * Each number must be an actual number to dial, not a dialing
+       directory entry.
+     * Dialing directory entries may not contain number lists in this
+       format.
+
+   In all other respects, the numbers are treated as if they had been
+   fetched from the dialing directory; they can be in literal or portable
+   format, etc. Example:
+
+  dial {{7654321} {+1 (212) 5551212} { 1-212-5556789 }}
+
+   The list can be any length at all, within reason.
+
+   This feature is especially handy for use with the K95 Dialer, allowing
+   a list of phone numbers to be specified in the Telephone Number box
+   without having to set up or reference a separate dialing directory.
+
+   You can also use it to add commonly-dialed sequences as variables in
+   your C-Kermit customization file, e.g.:
+
+  define work {{7654321}{7654322}{7654323}}
+
+   and then:
+
+  dial {\m(work)}
+
+   (the variable name must be enclosed in braces).
+
+   Or more simply:
+
+  define work dial {{7654321}{7654322}{7654323}}
+
+   and then:
+
+  work
+     _________________________________________________________________
+
+  2.2. Modems
+
+    2.2.1. New Modem Types
+
+   Since C-Kermit 6.0:
+
+  atlas-newcom-33600ifxC Atlas/Newcom 33600
+  att-keepintouch        AT&T KeepinTouch PCMCIA V.32bis Card Modem
+  att-1900-stu-iii       AT&T Secure Data STU-III Model 1900
+  att-1910-stu-iii       AT&T Secure Data STU-III Model 1910
+  bestdata               Best Data
+  cardinal               Cardinal V.34 MVP288X series.
+  compaq                 Compaq Data+Fax (e.g. in Presario)
+  fujitsu                Fujitsu Fax/Modem Adapter
+  generic-high-speed     Any modern error-correcting data-compressing modem
+  itu-t-v25ter/v250      ITU-T (CCITT) V.25ter (V.250) standard command set
+  megahertz-att-v34      Megahertz AT&T V.34
+  megahertz-xjack        Megahertz X-Jack
+  motorola-codex         Motorola Codex 326X Series
+  motorola-montana       Motorola Montana
+  mt5634zpx              Multitech MT5634ZPX
+  rockwell-v90           Rockwell V.90 56K
+  rolm-244pc             Siemens/Rolm 244PC (AT command set)
+  rolm-600-series        Siemens/Rolm 600 Series (AT command set)
+  spirit-ii              QuickComm Spirit II
+  suprasonic             SupraSonic V288+
+  supra-express-v90      Supra Express V.90
+
+   One of the new types, "generic-high-speed" needs a bit of explanation.
+   This type was added to easily handle other types that are not
+   explicitly covered, without going through the bother of adding a
+   complete user-defined modem type. This one works for modern modems
+   that use the AT command set, on the assumption that all the default
+   ("factory") settings of the modem (a) are appropriate for Kermit, (b)
+   include error correction, data compression, and speed buffering; and
+   (c) are recallable with the command AT&F.
+
+   If the command to recall your modem's profile is not AT&F, use the SET
+   MODEM COMMAND INIT-STRING command to specify the appropriate modem
+   command. The default init-string is AT&F\13 (that is, AT, ampersand,
+   F, and then carriage return); a survey of about 20 modern modem types
+   shows they all support this, but they might mean different things by
+   it. For example, the USR Sportster or Courier needs AT&F1 (not AT&F,
+   which is equivalent to AT&F0, which recalls an inappropriate profile),
+   so for USR modems:
+
+  set modem type generic-high-speed
+  set modem command init AT&F1\13
+
+   Of course, USR modems already have their own built-in modem type. But
+   if you use this one instead, it will dial faster because it has fewer
+   commands to give to the modem; in that sense "&F1" is like a macro
+   that bundles numerous commands into a single one. See your modem
+   manual for details about factory profiles and commands to recall them.
+
+   WARNING: Do not use the generic-high-speed modem type in operating
+   systems like VMS where hardware flow control is not available, at
+   least not unless you change the init string from AT&F\13 to something
+   else that enables local Xon/Xoff or other appropriate type of flow
+   control.
+
+   Also see [396]Section 2.1.7 for additional hints about making dialing
+   go faster.
+     _________________________________________________________________
+
+    2.2.2. New Modem Controls
+
+   SET MODEM CAPABILITIES list
+          In C-Kermit 7.0, this command automatically turns MODEM
+          SPEED-MATCHING OFF if SB (Speed Buffering) is in the list, and
+          turns it ON if SB is absent.
+
+   SET MODEM COMMAND PREDIAL-INIT [ text ]
+          Commands to be sent to the modem just prior to dialing.
+          Normally none.
+
+   SET MODEM SPEAKER { ON, OFF }
+          Determines whether modem speaker is on or off while call is
+          being placed. ON by default. Note: This command does not
+          provide fine-grained control over when the speaker is on or
+          off. Normally, ON means while the call is being placed, until
+          the point at which carrier is successfully established. If your
+          modem has a different speaker option that you want to choose,
+          then use the SET MODEM COMMAND SPEAKER ON text command to
+          specify this option.
+
+   SET MODEM COMMAND SPEAKER { ON, OFF } [ text ]
+          Specify or override the commands to turn your modem's speaker
+          on and off.
+
+   SET MODEM VOLUME { LOW, MEDIUM, HIGH }
+          When MODEM SPEAKER is on, select volume. Note: In some modems,
+          especially internal ones, these commands have no effect; this
+          is a limitation of the particular modem, not of Kermit.
+
+   SET MODEM COMMAND VOLUME { LOW, MEDIUM, HIGH } [ text ]
+          Specify or override the commands to set your modem's speaker
+          volume.
+
+   SET MODEM COMMAND IGNORE-DIALTONE [ text ]
+          The command to enable blind dialing ([397]Section 2.1.6).
+
+   SET MODEM ESCAPE-CHARACTER code
+          Has been augmented to allow codes of 0 or less: < 0 means the
+          escape mechanism is disabled. = 0 means to use (restore) the
+          default value from the modem database. > 0 and < 128 is a
+          literal value to be used instead of the default one. > 127
+          means the escape mechanism is disabled. This affects "modem
+          hangup". When the escape mechanism is disabled, but SET MODEM
+          HANGUP-METHOD is MODEM-COMMAND, it sends the hangup command
+          immediately, without the <pause>+++<pause> business first. This
+          is useful (for example) when sending lots of numeric pages, a
+          process in which never we go online, and so never need to
+          escape back. Eliminating the unnecessary pauses and escape
+          sequence allows a lot more pages to be sent per unit time.
+
+   Recall that C-Kermit can dial modems to which it is connected via
+   TCP/IP (Telnet or Rlogin) as described on page 126 of [398]Using
+   C-Kermit, 2nd Ed. In this case the MODEM HANGUP-METHOD should be
+   MODEM-COMMAND, since RS-232 signals don't work over TCP/IP
+   connections. As noted in the manual, such connections are set up by
+   the following sequence:
+
+  set host host [ port ]
+  set modem type name
+  dial number
+
+   But this can cause complications when you use Kermit to switch between
+   serial and TCP/IP connections. In the following sequence:
+
+  set host name
+  set modem type name
+  set port name
+
+   the first two commands obey the rules for dialing out over Telnet.
+   However, the SET PORT command requires that Kermit close its current
+   (Telnet) connection before it can open the serial port (since Kermit
+   can only have one connection open at a time). But since a modem type
+   was set after the "set host" command was given, Kermit assumes it is a
+   Telnet dialout connection and so sends the modem's hangup sequence is
+   sent to the Telnet host. To avoid this, close the network connection
+   explicitly before opening the serial one:
+
+  set host name
+  close
+  set modem type name
+  set port name
+     _________________________________________________________________
+
+  2.3. TELNET and RLOGIN
+
+   For additional background, please also read the [399]TELNET.TXT file,
+   also available on the Web in [400]HTML format.
+
+   Cautions:
+
+     * If making a Telnet connection with C-Kermit takes a very long
+       time, like over a minute, whereas the system Telnet program makes
+       the same connection immediately, try including the /NOWAIT switch:
+  C-Kermit> telnet /nowait hostname
+       See [401]TELNET.TXT or [402]TELNET.HTM for details. If it also
+       takes a very long time to make a Telnet connection with system
+       Telnet, then the delay is most likely caused by reverse DNS
+       lookups when your host is not properly registered in DNS.
+     * When supplying numeric IP addresses to C-Kermit or to any other
+       application (regular Telnet, Rlogin, etc), do not include leading
+       0's in any fields unless you intend for those fields to be
+       interpreted as octal (or hex) numbers. The description of the
+       Internet address interpreter (the sockets library inet_addr()
+       routine) includes these words:
+
+     All numbers supplied as "parts" in a "." notation may be decimal,
+     octal, or hexadecimal, as specified in the C language (that is, a
+     leading 0x or 0X implies hexadecimal; otherwise, a leading 0
+     implies octal; otherwise, the number is interpreted as decimal).
+       To illustrate, 128.59.39.2 and 128.059.039.002 are not the same
+       host! Even though most of the fields contain non-octal digits.
+       Using system Telnet (not Kermit):
+  $ telnet 128.059.039.002
+  Trying 128.49.33.2 ...
+       Of course the same thing happens with Kermit because it uses (as
+       it must) the same system service for resolving network addresses
+       that Telnet, FTP, and all other TCP/IP applications use.
+     * The RLOGIN section on page 123 does not make it clear that you can
+       use the SET TELNET TERMINAL-TYPE command to govern the terminal
+       type that is reported by C-Kermit to the RLOGIN server.
+     * Note that the SET TCP commands described on pages 122-123 might be
+       absent; some platforms that support TCP/IP do not support these
+       particular controls.
+
+   New commands:
+
+   TELOPT { AO, AYT, BREAK, CANCEL, EC, EL, EOF, EOR, GA, IP, DMARK,
+          DO, DONT, NOP, SB, SE, SUSP, WILL, WONT }
+          This command was available previously, but supported only DO,
+          DONT, WILL, and WONT. Now it lets you send all the Telnet
+          protocol commands. Note that certain commands do not require a
+          response, and therefore can be used as nondestructive "probes"
+          to see if the Telnet session is still open; e.g.:
+
+  set host xyzcorp.com
+  ...
+  telopt nop
+  if fail stop 1 Connection lost
+
+   SET TCP ADDRESS [ ip-address ]
+          Specifies the IP address of the computer that C-Kermit is
+          running on. Normally this is not necessary. The exception would
+          be if your machine has multiple network adapters (physical or
+          virtual) with a different address for each adapter AND you want
+          C-Kermit to use a specific address when making outgoing
+          connections or accepting incoming connections.
+
+   SET TCP DNS-SERVICE-RECORDS { ON, OFF }
+          Tells C-Kermit whether to try to use DNS SRV records to
+          determine the host and port number upon which to find an
+          advertised service. For example, if a host wants regular Telnet
+          connections redirected to some port other than 23, this feature
+          allows C-Kermit to ask the host which port it should use. Since
+          not all domain servers are set up to answer such requests, this
+          feature is OFF by default.
+
+   SET TCP REVERSE-DNS-LOOKUP { ON, OFF, AUTO }
+          Tells Kermit whether to perform a reverse DNS lookup on TCP/IP
+          connections. This allows Kermit to determine the actual
+          hostname of the host it is connected to, which is useful for
+          connections to host pools, and is required for Kerberos
+          connections to host pools and for incoming connections. If the
+          other host does not have a DNS entry, the reverse lookup could
+          take a long time (minutes) to fail, but the connection will
+          still be made. Turn this option OFF for speedier connections if
+          you do not need to know exactly which host you are connected to
+          and you are not using Kerberos. AUTO, the default, means the
+          lookup is done on hostnames, but not on numeric IP addresses.
+
+   SET TELNET WAIT-FOR-NEGOTIATIONS { ON, OFF }
+          Each Telnet option must be fully negotiated either On or Off
+          before the session can continue. This is especially true with
+          options that require sub-negotiations such as Authentication,
+          Encryption, and Kermit; for proper support of these options
+          Kermit must wait for the negotiations to complete. Of course,
+          Kermit has no way of knowing whether a reply is delayed or not
+          coming at all, and so will wait a minute or more for required
+          replies before continuing the session. If you know that
+          Kermit's Telnet partner will not be sending the required
+          replies, you can set this option of OFF to avoid the long
+          timeouts. Or you can instruct Kermit to REFUSE specific options
+          with the SET TELOPT command.
+
+   SET TELOPT [ { /CLIENT, /SERVER } ] option
+          { ACCEPTED, REFUSED, REQUESTED, REQUIRED }
+          [ { ACCEPTED, REFUSED, REQUESTED, REQUIRED } ]
+          SET TELOPT lets you specify policy requirements for Kermit's
+          handling of Telnet option negotiations. Setting an option is
+          REQUIRED causes Kermit to offer the option to the peer and
+          disconnect if the option is refused. REQUESTED causes Kermit to
+          offer an option to the peer. ACCEPTED results in no offer but
+          Kermit will attempt to negotiate the option if it is requested.
+          REFUSED instructs Kermit to refuse the option if it is
+          requested by the peer.
+
+          Some options are negotiated in two directions and accept
+          separate policies for each direction; the first keyword applies
+          to Kermit itself, the second applies to Kermit's Telnet
+          partner; if the second keyword is omitted, an appropriate
+          (option-specific) default is applied. You can also include a
+          /CLIENT or /SERVER switch to indicate whether the given
+          policies apply when Kermit is the Telnet client or the Telnet
+          server; if no switch is given, the command applies to the
+          client.
+
+          Note that some of Kermit's Telnet partners fail to refuse
+          options that they do not recognize and instead do not respond
+          at all. In this case it is possible to use SET TELOPT to
+          instruct Kermit to REFUSE the option before connecting to the
+          problem host, thus skipping the problematic negotiation.
+
+          Use SHOW TELOPT to view current Telnet Option negotiation
+          settings. SHOW TELNET displays current Telnet settings.
+     _________________________________________________________________
+
+    2.3.0. Bug Fixes
+
+   If "set host nonexistent-host" was given (and it properly failed),
+   followed by certain commands like SEND, the original line and modem
+   type were not restored and C-Kermit thought that it still had a
+   network hostname; fixed in 7.0.
+
+    2.3.1. Telnet Binary Mode Bug Adjustments
+
+   SET TELNET BUG BINARY-ME-MEANS-U-TOO { ON, OFF } was added to edit 192
+   after the book was printed. Also SET TELNET BUG BINARY-U-MEANS-ME-TOO.
+   The default for both is OFF. ON should be used when communicating with
+   a Telnet partner (client or server) that mistakenly believes that
+   telling C-Kermit to enter Telnet binary mode also means that it, too,
+   is in binary mode, contrary to the Telnet specification, which says
+   that binary mode must be negotiated in each direction separately.
+
+    2.3.2. VMS UCX Telnet Port Bug Adjustment
+
+   A new command, SET TCP UCX-PORT-BUG, was added for VMS versions with
+   UCX (DEC TCP/IP), applying only to early versions of UCX, like 2.2 or
+   earlier. If you try to use VMS C-Kermit to make a Telnet connection
+   using a port name (like "telnet", which is used by default), the
+   underlying UCX getservbyname() function might return the service
+   number with its bytes swapped and the connection will fail. If "telnet
+   hostname 23" works, then your version of UCX has this bug and you can
+   put "set tcp ucx-port-bug on" in your CKERMIT.INI file to get around
+   it.
+
+    2.3.3. Telnet New Environment Option
+
+   The TELNET NEW-ENVIRONMENT option ([403]RFC 1572) is supported as 7.0.
+   This option allows the C-Kermit Telnet client to send certain
+   well-known variables to the Telnet server, including USER, PRINTER,
+   DISPLAY, and several others. This feature is enabled by default in
+   Windows and OS/2, disabled by default elsewhere. The command to enable
+   and disable it is:
+
+  SET TELNET ENVIRONMENT { ON, OFF }
+
+   When ON, and you Telnet to another computer, you might (or might not)
+   notice that the "login:" or "Username:" prompt does not appear --
+   that's because your username was sent ahead, in which case the remote
+   system might prompt you only for your password (similar to Rlogin).
+   Use "set telnet environment off" to defeat this feature, particularly
+   in scripts where the dialog must be predictable. You can also use this
+   command to specify or override specific well-known environment
+   variable values:
+
+ SET TELNET ENVIRONMENT { ACCT,DISPLAY,JOB,PRINTER,SYSTEMTYPE,USER } [ text ]
+
+    2.3.4. Telnet Location Option
+
+   The TELNET LOCATION option ([404]RFC 779) is supported in 7.0. This
+   option allows the C-Kermit Telnet client to send a location string to
+   the server if the server indicates its willingness to accept one. If
+   an environment variable named LOCATION exists at the time C-Kermit
+   starts, its value is used as the location string. If you want to
+   change it, use:
+
+  SET TELNET LOCATION text
+
+   If you omit the text from this command, the Telnet location feature is
+   disabled.
+
+   SET TELNET ENVIRONMENT DISPLAY is used to set the DISPLAY variable
+   that is sent to the host, as well as the the XDISPLAY location.
+
+    2.3.5. Connecting to Raw TCP Sockets
+
+   The SET HOST and TELNET commands now accept an optional switch,
+   /RAW-SOCKET, at the end, only if you first give a host and a port.
+   Example:
+
+  set host xyzcorp.com 23 /raw-socket
+  set host 128.49.39.2:2000 /raw-socket
+  telnet xyzcorp.com 3000 /raw
+
+   Without this switch, C-Kermit behaves as a Telnet client when (a) the
+   port is 23 or 1649, or (b) the port is not 513 and the server sent
+   what appeared to be Telnet negotiations -- that is, messages starting
+   with 0xFF (IAC). With this switch, Kermit should treat all incoming
+   bytes as raw data, and will not engage in any Telnet negotiations or
+   NVT CRLF manipulations. This allows transparent operation through
+   (e.g.) raw TCP ports on Cisco terminal servers, through the 'modemd'
+   modem server, etc.
+
+    2.3.6. Incoming TCP Connections
+
+   Accomplished via SET HOST * port, were introduced in C-Kermit 6.0, but
+   for UNIX only. In Version 7.0, they are also available for VMS.
+     _________________________________________________________________
+
+  2.4. The EIGHTBIT Command
+
+   EIGHTBIT is simply a shorthand for: SET PARITY NONE, SET TERMINAL
+   BYTESIZE 8, SET COMMAND BYTESIZE 8; that is, a way to set up an 8-bit
+   clean connection in a single command.
+     _________________________________________________________________
+
+  2.5. The Services Directory
+
+   Chapter 7 of [405]Using C-Kermit does not mention the ULOGIN macro,
+   which is used by our sample services directory, CKERMIT.KND. Unlike
+   UNIXLOGIN, VMSLOGIN, etc, this one is for use with systems that
+   require a user ID but no password. Therefore it doesn't prompt for a
+   password or wait for a password prompt from the remote service.
+
+   In version 7.0, the CALL macro was changed to not execute a SET MODEM
+   TYPE command if the given modem type was the same as the current one;
+   otherwise the new SET MODEM TYPE command would overwrite any
+   customizations that the user had made to the modem settings. Ditto for
+   SET LINE / SET PORT and SET SPEED.
+     _________________________________________________________________
+
+  2.6. Closing Connections
+
+   Until version 7.0, there was never an obvious and general way to close
+   a connection. If a serial connection was open, it could be closed by
+   "set line" or "set port" (giving no device name); if a network
+   connection was open, it could be closed by "set host" (no host name).
+
+   In version 7.0, a new command closes the connection in an obvious and
+   straightforward way, no matter what the connection type:
+
+  CLOSE [ CONNECTION ]
+
+   The CLOSE command was already present, and required an operand such as
+   DEBUG-LOG, WRITE-FILE, etc, and so could never be given by itself. The
+   new CONNECTION operand is now the default operand for CLOSE, so CLOSE
+   by itself closes the connection, if one is open, just as you would
+   expect, especially if you are a Telnet or Ftp user.
+
+   Also see the description of the new SET CLOSE-ON-DISCONNECT command in
+   [406]Section 2.10.
+     _________________________________________________________________
+
+  2.7. Using C-Kermit with External Communication Programs
+
+   C-Kermit 7.0 includes a new ability to create and conduct sessions
+   through other communications programs. Two methods are available:
+
+    1. Pty (pseudoterminal): The external program is run on a
+       "pseudoterminal", which is controlled by Kermit. This method works
+       with practically any external program, but it is not portable. At
+       this writing, it works only on some (not all) UNIX versions, and
+       not on any non-UNIX platforms.
+    2. Pipe: The external program's standard input and output are
+       redirected through a "pipe" controlled by Kermit. This method is
+       relatively portable -- it should work across all UNIX versions,
+       and it also works in Windows and OS/2 -- but it is effective only
+       when the external program actually uses standard i/o (and many
+       don't).
+
+   The two methods are started differently but are used the same way
+   thereafter.
+
+   The purpose of this feature is to let you use C-Kermit services like
+   file transfer, character-set translation, scripting, automatic
+   dialing, etc, on connections that Kermit can't otherwise make itself.
+
+   This feature is the opposite of the REDIRECT feature, in which
+   C-Kermit makes the connection, and redirects an external (local)
+   command or program over this connection. In a pty or pipe connection,
+   C-Kermit runs and controls a local command or program, which makes the
+   connection. (The same method can be used to simply to control a local
+   program without making a connection; see [407]Section 2.8.)
+
+   To find out if your version of Kermit includes PTY support, type "show
+   features" and look for NETPTY in the alphabetical list of options. For
+   pipes, look for NETCMD.
+
+   The commands are:
+
+   SET NETWORK TYPE PTY or SET NETWORK TYPE PIPE
+   SET HOST command
+          where command is any interactive command. If the command does
+          not use standard i/o, you must use SET NETWORK TYPE PTY.
+
+   Notes:
+
+     * COMMAND is an invisible synonym for PIPE.
+     * The command and its arguments are case-sensitive in UNIX.
+
+   The SET NETWORK TYPE, SET HOST sequence sets the given network type
+   for all subsequent SET HOST commands until another SET NETWORK TYPE
+   command is given to change it.
+
+   You can also use the new /NETWORK-TYPE:PTY or /NETWORK-TYPE:PIPE (or
+   simply /PIPE or /PTY) switches on the SET HOST command itself:
+
+  SET HOST /NETWORK-TYPE:PIPE command  ; These two are the same
+  SET HOST /PIPE command
+
+  SET HOST /NETWORK-TYPE:PTY command   ; Ditto
+  SET HOST /PTY command
+
+   These are like SET NETWORK TYPE followed by SET HOST, except they
+   apply only to the connection being made and do not change the global
+   network type setting (see [408]Section 1.5 about the difference
+   between switches and SET commands).
+
+   Include any command-line options with the command that might be
+   needed, as in this example where C-Kermit uses another copy of itself
+   as the communications program:
+
+  SET HOST /PIPE /CONNECT kermit -YQJ xyzcorp.com
+
+   As usual, if you include the /CONNECT switch, SET HOST enters CONNECT
+   mode immediately upon successful execution of the given command.
+   Therefore new commands are available as a shorthand for SET HOST
+   /CONNECT /PTY and /PIPE:
+
+   PTY [ command ]
+   PIPE [ command ]
+          The PTY and PIPE commands work like the TELNET and RLOGIN
+          commands: they set up the connection (in this case, using the
+          given command) and then enter CONNECT mode automatically (if
+          the PIPE or PTY command is given without a command, it
+          continues the current session if one is active; otherwise it
+          gives an error message).
+
+   The PIPE command is named after the mechanism by which C-Kermit
+   communicates with the command: UNIX pipes. C-Kermit's i/o is "piped"
+   through the given command. Here is a typical example:
+
+  PIPE rlogin -8 xyzcorp.com
+
+   This is equivalent to:
+
+  SET HOST /PIPE rlogin -8 xyzcorp.com
+  CONNECT
+
+   and to:
+
+  SET HOST /PIPE /CONNECT rlogin -8 xyzcorp.com
+
+   IMPORTANT:
+          If you are writing a script, do not use the PIPE, PTY, TELNET,
+          or RLOGIN command unless you really want C-Kermit to enter
+          CONNECT mode at that point. Normally SET HOST is used in
+          scripts to allow the login and other dialogs to be controlled
+          by the script itself, rather than by an actively participating
+          human at the keyboard.
+
+   Throughput of pty and pipe connections is limited by the performance
+   of the chosen command or program and by the interprocess communication
+   (IPC) method used and/or buffering capacity of the pipe or pty, which
+   in turn depends on the underlying operating system.
+
+   In one trial (on SunOS 4.1.3), we observed file transfer rates over an
+   rlogin connection proceeding at 200Kcps for downloads, but only 10Kcps
+   for uploads on the same connection with the same settings (similar
+   disparities were noted in HP-UX). Examination of the logs revealed
+   that a write to the pipe could take as long as 5 seconds, whereas
+   reads were practically instantaneous. On the other hand, using Telnet
+   as the external program rather than rlogin, downloads and uploads were
+   better matched at about 177K each.
+
+   Most external communication programs, like C-Kermit itself, have
+   escape characters or sequences. Normally these begin with (or consist
+   entirely of) a control character. You must be sure that this control
+   character is not "unprefixed" when uploading files, otherwise the
+   external program will "escape back" to its prompt, or close the
+   connection, or take some other unwanted action. When in CONNECT mode,
+   observe the program's normal interaction rules. Of course C-Kermit's
+   own escape character (normally Ctrl-\) is active too, unless you have
+   taken some action to disable it.
+
+   On PTY connections, the underlying PTY driver is not guaranteed to be
+   transparent to control characters -- for example, it might expand
+   tabs, translate carriage returns, generate signals if it sees an
+   interrupt character, and so on. Similar things might happen on a PIPE
+   connection. For this reason, if you plan to transfer files over a PTY
+   or PIPE connection, tell the file sender to:
+
+   SET PREFIXING ALL
+          This causes all control characters to be prefixed and
+          transmitted as printable ASCII characters.
+
+   If the external connection program is not 8-bit clean, you should
+   also:
+
+   SET PARITY SPACE
+          This causes 8-bit data to be encoded in 7 bits using single
+          and/or locking shifts.
+
+   And if it does not make a reliable connection (such as those made by
+   Telnet, Rlogin, Ssh, etc), you should:
+
+   SET STREAMING OFF
+          This forces C-Kermit to treat the connection as unreliable and
+          to engage in its normal ACK/NAK protocol for error detection
+          and correction, rather than "streaming" its packets, as it
+          normally does on a network connection ([409]Section 4.20).
+
+   In some cases, buffer sizes might be restricted, so you might also
+   need to reduce the Kermit packet length to fit; this is a
+   trial-and-error affair. For example, if transfers always fail with
+   4000-byte packets, try 2000. If that fails too, try 1000, and so on.
+   The commands are:
+
+   SET RECEIVE PACKET-LENGTH number
+          This tells the file receiver to tell the file sender the
+          longest packet length it can accept.
+
+   SET SEND PACKET-LENGTH number
+          This tells the file sender not to send packets longer than the
+          given length, even if the receiver says longer ones are OK. Of
+          course, if the receiver's length is shorter, the shorter length
+          is used.
+
+   If none of this seems to help, try falling back to the bare minimum,
+   lowest-common-denominator protocol settings:
+
+   ROBUST
+          No sliding windows, no streaming, no control-character
+          unprefixing, packet length 90.
+
+   And then work your way back up by trial and error to get greater
+   throughput.
+
+   Note that when starting a PIPE connection, and the connection program
+   (such as telnet or rlogin) prints some greeting or information
+   messages before starting the connection, these are quite likely to be
+   printed with a stairstep effect (linefeed without carriage return).
+   This is because the program is not connected with the UNIX terminal
+   driver; there's not much Kermit can do about it. Once the connection
+   is made, everything should go back to normal. This shouldn't happen on
+   a PTY connection because a PTY is, indeed, a terminal.
+
+   On a similar note, some connection programs (like Solaris 2.5 rlogin)
+   might print lots of error messages like "ioctl TIOCGETP: invalid
+   argument" when used through a pipe. They are annoying but usually
+   harmless. If you want to avoid these messages, and your shell allows
+   redirection of stderr, you can redirect stderr in your pipe command,
+   as in this example where the user's shell is bash:
+
+  PIPE rlogin xyzcorp.com 2> /dev/null
+
+   Or use PTY rather than PIPE, since PTY is available on Solaris.
+     _________________________________________________________________
+
+    2.7.0. C-Kermit over tn3270 and tn5250
+
+   Now you can make a connection from C-Kermit "directly" to an IBM
+   mainframe and transfer files with it, assuming it has Kermit-370
+   installed. Because tn3270 is neither 8-bit clean nor transparent to
+   control characters, you must give these commands:
+
+  SET PREFIXING ALL   ; Prefix all control characters
+  SET PARITY SPACE    ; Telnet connections are usually not 8-bit clean
+
+   and then:
+
+  SET HOST /PTY /CONNECT tn3270 abccorp.com
+
+   or simply:
+
+  pty tn3270 abccorp.com
+
+   SET HOST /PIPE does not work in this case, at least not for file
+   transfer. File transfer does work, however, with SET HOST /PTY,
+   provided you use the default packet length of 90 bytes; anything
+   longer seems to kill the session.
+
+   You can also make connections to IBM AS/400 computers if you have a
+   tn5250 program installed:
+
+  pty tn5250 hostname
+
+   In this case, however, file transfer is probably not in the cards
+   since nobody has ever succeeded in writing a Kermit program for the
+   AS/400. Hint:
+
+  define tn3270 {
+      check pty
+      if fail end 1 Sorry - no PTY support...
+      pty tn3270 \%*
+  }
+
+   Similarly for tn5250. Note that CHECK PTY and CHECK PIPE can be used
+   in macros and scripts to test whether PTY or PIPE support is
+   available.
+     _________________________________________________________________
+
+    2.7.1. C-Kermit over Telnet
+
+   Although C-Kermit includes its own Telnet implementation, you might
+   need to use an external Telnet program to make certain connections;
+   perhaps because it has access or security features not available in
+   C-Kermit itself. As noted above, the only precautions necessary are
+   usually:
+
+  SET PREFIXING ALL   ; Prefix all control characters
+  SET PARITY SPACE    ; Telnet connections might not be 8-bit clean
+
+   and then:
+
+  SET HOST /PTY (or /PIPE) /CONNECT telnet abccorp.com
+
+   or, equivalently:
+
+  PTY (or PIPE) telnet abccorp.com
+     _________________________________________________________________
+
+    2.7.2. C-Kermit over Rlogin
+
+   C-Kermit includes its own Rlogin client, but this can normally be used
+   only if you are root, since the rlogin TCP port is privileged. But
+   ptys and pipes let you make rlogin connections with C-Kermit through
+   your computer's external rlogin program, which is normally installed
+   as a privileged program:
+
+  SET PREFIXING ALL
+
+   and then:
+
+  SET HOST /PTY (or /PIPE) /CONNECT rlogin -8 abccorp.com
+
+   or, equivalently:
+
+  PTY (or PIPE) rlogin -8 abccorp.com
+
+   The "-8" option to rlogin enables transmission of 8-bit data. If this
+   is not available, then include SET PARITY SPACE if you intend to
+   transfer files.
+
+   Note that the normal escape sequence for rlogin is Carriage Return
+   followed by Tilde (~), but only when the tilde is followed by certain
+   other characters; the exact behavior depends on your rlogin client, so
+   read its documentation.
+     _________________________________________________________________
+
+    2.7.3. C-Kermit over Serial Communication Programs
+
+   Ptys and pipes also let you use programs that make serial connections,
+   such as cu or tip. For example, C-Kermit can be used through cu to
+   make connections that otherwise might not be allowed, e.g. because
+   C-Kermit is not installed with the required write permissions to the
+   dialout device and the UUCP lockfile directory.
+
+   Suppose your UUCP Devices file contains an entry for a serial device
+   tty04 to be used for direct connections, but this device is protected
+   against you (and Kermit when you run it). In this case you can:
+
+  SET CONTROL PREFIX ALL
+  PTY (or PIPE) cu -l tty04
+
+   (Similarly for dialout devices, except then you also need to include
+   the phone number in the "cu" command.)
+
+   As with other communication programs, watch out for cu's escape
+   sequence, which is the same as the rlogin program's: Carriage Return
+   followed by Tilde (followed by another character to specify an action,
+   like "." for closing the connection and exiting from cu).
+     _________________________________________________________________
+
+    2.7.4. C-Kermit over Secure Network Clients
+
+     DISCLAIMER: There are laws in the USA and other countries regarding
+     use, import, and/or export of encryption and/or decryption or other
+     forms of security software, algorithms, technology, and
+     intellectual property. The Kermit Project attempts to follow all
+     known statutes, and neither intends nor suggests that Kermit
+     software can or should be used in any way, in any location, that
+     circumvents any regulations, laws, treaties, covenants, or other
+     legitimate canons or instruments of law, international relations,
+     trade, ethics, or propriety.
+
+   For secure connections or connections through firewalls, C-Kermit 7.0
+   can be a Kerberos, SRP, and/or SOCKS client when built with the
+   appropriate options and libraries. But other application-level
+   security acronyms and methods -- SSH, SSL, SRP, TLS -- pop up at an
+   alarming rate and are (a) impossible to keep up with, (b) usually
+   mutually incompatible, and (c) have restrictions on export or
+   redistribution and so cannot be included in C-Kermit itself.
+
+   However, if you have a secure text-based Telnet (or other) client that
+   employs one of these security methods, you can use C-Kermit "through"
+   it via a pty or pipe.
+     _________________________________________________________________
+
+    2.7.4.1. SSH
+
+   C-Kermit does not and can not incorporate SSH due to licensing,
+   patent, and USA export law restrictions.
+
+   The UNIX SSH client does not use standard input/output, and therefore
+   can be used only by Kermit's PTY interface, if one is present. The
+   cautions about file transfer, etc, are the same as for Rlogin.
+   Example:
+
+  SET PREFIXING ALL
+  PTY ssh XYZCORP.COM
+
+   Or, for a scripted session:
+
+  SET PREFIXING ALL
+  SET HOST /PTY ssh XYZCORP.COM
+
+   Hint:
+
+  define ssh {
+      check pty
+      if fail end 1 Sorry - no PTY support...
+      pty ssh \%*
+  }
+     _________________________________________________________________
+
+    2.7.4.2. SSL
+
+   Secure Sockets Layer (SSL) is another TCP/IP security overlay, this
+   one designed by and for Netscape. An SSL Telnet client is available
+   for UNIX from the University of Queensland. More info at:
+
+  [410]http://www.psy.uq.oz.au/~ftp/Crypto/
+
+   Interoperability with C-Kermit is unknown. C-Kermit also includes its
+   own built-in SSL/TLS support, but it is not exportable; [411]CLICK
+   HERE file for details.
+     _________________________________________________________________
+
+    2.7.4.3. SRP
+
+   SRP(TM) is Stanford University's Secure Remote Password protocol. An
+   SRP Telnet client is available from Stanford:
+
+  [412]http://srp.stanford.edu/srp/
+
+   Stanford's SRP Telnet client for UNIX has been tested on SunOS and
+   works fine with C-Kermit, as described in [413]Section 2.7.1, e.g.
+
+  SET PREFIX ALL
+  PTY (or PIPE) srp-telnet xenon.stanford.edu
+
+   C-Kermit itself can be built as an SRP Telnet client on systems that
+   have libsrp.a installed; the C-Kermit support code, however, may not
+   be exported outside the USA or Canada.
+     _________________________________________________________________
+
+    2.7.4.4. SOCKS
+
+   C-Kermit can be built as a SOCKS-aware client on systems that have a
+   SOCKS library. See section 8.1.1 of the [414]ckccfg.txt file.
+
+   C-Kermit 7.0 can also be run over SOCKSified Telnet or rlogin clients
+   with SET NETWORK TYPE COMMAND. Suppose the Telnet program on your
+   system is SOCKS enabled but C-Kermit is not. Make Kermit connections
+   like this:
+
+  SET PREFIX ALL
+  PTY (or PIPE) telnet zzz.com
+     _________________________________________________________________
+
+    2.7.4.5. Kerberos
+
+   UNIX C-Kermit can be built with MIT Kerberos IV or V authentication
+   and encryption. Instructions are available in a [415]separate
+   document. Additional modules are required that can not be exported
+   from the USA to any country except Canada, by US law.
+
+   If you have Kerberos installed but you don't have a Kerberized version
+   of C-Kermit, you can use ktelnet as C-Kermit's external communications
+   program to make secure connections without giving up C-Kermit's
+   services:
+
+  SET PREFIX ALL
+  PTY (or PIPE) ktelnet cia.gov
+     _________________________________________________________________
+
+  2.8. Scripting Local Programs
+
+   If your version of Kermit has PTY support built in, then any
+   text-based program can be invoked with SET HOST /PTY or equivalent
+   command and controlled using the normal sequence of OUTPUT, INPUT, IF
+   SUCCESS commands (this is the same service that is provided by the
+   'expect' program, but controlled by the Kermit script language rather
+   than Tcl).
+
+   When PTY service is not available, then any program that uses standard
+   input and output can be invoked with SET HOST /PIPE.
+
+   Here's an example in which we start an external Kermit program, wait
+   for its prompt, give it a VERSION command, and then extract the
+   numeric version number from its response:
+
+  set host /pty kermit -Y
+  if fail stop 1 {Can't start external command}
+  input 10 C-Kermit>
+  if fail stop 1 {No C-Kermit> prompt}
+  output version\13
+  input 10 {Numeric: }
+  if fail stop 1 {No match for "Numeric:"}
+  clear input
+  input 10 \10
+  echo VERSION = "\fsubstr(\v(input),1,6)"
+  output exit\13
+
+   This technique could be used to control any other interactive program,
+   even those that do screen formatting (like Emacs or Vi), if you can
+   figure out the sequence of events. If your Kermit program doesn't have
+   PTY support, then the commands are restricted to those using standard
+   i/o, including certain shells, interactive text-mode "hardcopy"
+   editors like ex, and so on.
+
+   If you are using the PTY interface, you should be aware that it runs
+   the given program or command directly on the pty, without any
+   intervening shell to interpret metacharacters, redirectors, etc. If
+   you need this sort of thing, include the appropriate shell invocation
+   as part of your command; for example:
+
+  pty echo *
+
+   just echoes "*"; whereas:
+
+  pty ksh -c "echo *"
+
+   echoes all the filenames that ksh finds matching "*".
+
+   Similarly for redirection:
+
+  set host /pty ksh -c "cat > foo"  ; Note: use shell quoting rules here
+  set transmit eof \4
+  transmit bar
+
+   And for that matter, for built-in shell commands:
+
+  set host /pty ksh -c "for i in *; do echo $i; done"
+
+   The PIPE interface, on the other hand, invokes the shell
+   automatically, so:
+
+  pipe echo *
+
+   prints filenames, not "*".
+     _________________________________________________________________
+
+  2.9. X.25 Networking
+
+   X.25 networking is documented in [416]Using C-Kermit, 2nd Edition.
+   When the book was published, X.25 was available only in SunOS,
+   Solaris, and Stratus VOS. Unlike TCP/IP, X.25 APIs are not
+   standardized; each vendor's X.25 libraries and services (if they have
+   them at all) are unique.
+
+   This section describes new additions.
+     _________________________________________________________________
+
+    2.9.1. IBM AIXLink/X.25 Network Provider Interface for AIX
+
+   Support for X.25 was added via IBM's Network Provider Interface (NPI),
+   AIXLink/X.25 1.1, to the AIX 4.x version of C-Kermit 7.0.
+   Unfortunately, AIXLink/X.25 is a rather bare-bones facility, lacking
+   in particular any form of PAD support (X.3, X.28, X.29). Thus, the AIX
+   version of C-Kermit, when built to include X.25 networking, has
+   neither a PAD command, nor a SET PAD command. The same is true for the
+   underlying AIX system: no PAD support. Thus it is not possible to have
+   an interactive shell session over an X.25 connection into an AIX
+   system (as far as we know), even from X.25-capable Kermit versions
+   (such as Solaris or VOS) that do include PAD support.
+
+   Thus the X.25 capabilities in AIX C-Kermit are limited to peer-to-peer
+   connections, e.g. from a C-Kermit client to a C-Kermit server. Unlike
+   the Solaris, SunOS, and VOS versions, the AIX version can accept
+   incoming X.25 connections:
+
+  set network type x.25
+  if fail stop 1 Sorry - no X.25 support
+  ; Put any desired DISABLE or ENABLE or SET commands here.
+  set host /server *
+  if fail stop 1 X.25 "set host *" failed
+
+   And then access it from the client as follows:
+
+  set network type x.25
+  if fail stop 1 Sorry - no X.25 support
+  set host xxxxxxx ; Specify the X.25/X.121 address
+  if fail stop 1 Can't open connection
+
+   And at this point the client can use the full range of client
+   commands: SEND, GET, REMOTE xxx, FINISH, BYE.
+
+   The AIX version also adds two new variables:
+
+   \v(x25local_nua)
+          The local X.25 address.
+
+   \v(x25remote_nua)
+          The X.25 address of the host on the other end of the
+          connection.
+
+   C-Kermit's AIX X.25 client has not been tested against anything other
+   than a C-Kermit X.25 server on AIX. It is not known if it will
+   interoperate with C-Kermit servers on Solaris, SunOS, or VOS.
+
+   To make an X.25 connection from AIX C-Kermit, you must:
+
+  set x25 call-user-data xxxx
+
+   where xxxx can be any even-length string of hexadecimal digits, e.g.
+   123ABC.
+     _________________________________________________________________
+
+    2.9.2. HP-UX X.25
+
+   Although C-Kermit presently does not include built-in support for
+   HP-UX X.25, it can still be used to make X.25 connections as follows:
+   start Kermit and tell it to:
+
+  set prefixing all
+  set parity space
+  pty padem address
+
+   This should work in HP-UX 9.00 and later (see [417]Section 2.7). If
+   you have an earlier HP-UX version, or the PTY interface doesn't work
+   or isn't available, try:
+
+  set prefixing all
+  set parity space
+  pipe padem address
+
+   Failing that, use Kermit to telnet to localhost and then after logging
+   back in, start padem as you would normally do to connect over X.25.
+     _________________________________________________________________
+
+  2.10. Additional Serial Port Controls
+
+   C-Kermit 7.0 adds the following commands for greater control over
+   serial ports. These commands are available only in C-Kermit versions
+   whose underlying operating systems provide the corresponding services
+   (such as POSIX and UNIX System V), and even then their successful
+   operation depends on the capabilities of the specific device and
+   driver.
+
+   SET DISCONNECT { ON, OFF }
+          On a SET LINE or SET PORT connection with SET CARRIER ON or
+          AUTO, if the carrier signal drops during the connection,
+          indicating that the connection has been lost, and C-Kermit
+          notices it, this setting governs what happens next. With SET
+          DISCONNECT OFF, which is consistent with previous behavior, and
+          therefore the default, C-Kermit continues to keep the device
+          open and allocated. With SET DISCONNECT ON, C-Kermit
+          automatically closes and releases the device when it senses a
+          carrier on-to-off transition, thus allowing others to use it.
+          However, it remains the default device for i/o (DIAL, REDIAL,
+          INPUT, SEND, CONNECT, etc), so if a subsequent i/o command is
+          given, the device is reopened if it is still available. When it
+          has been automatically closed in this manner, SHOW
+          COMMUNICATIONS puts "(closed)" after its name, and in UNIX, the
+          lockfile disappears -- both from SHOW COMM and from the
+          lockfile directory itself. Synonym: SET CLOSE-ON-DISCONNECT.
+
+   SET EXIT ON-DISCONNECT { ON, OFF }
+          Like DISCONNECT, but makes the program exit if a connection
+          drops.
+
+   Note that SET CLOSE-ON-DISCONNECT and SET EXIT ON-DISCONNECT apply
+   only to connections that drop; they do not apply to connections that
+   can't be made in the first place. For example, they have no effect
+   when a SET LINE, SET HOST, TELNET, or DIAL command fails.
+
+   HANGUP
+          If [CLOSE-ON-]DISCONNECT is ON, and the HANGUP command is given
+          on a serial device, and the carrier signal is no longer present
+          after the HANGUP command, the device is closed and released.
+
+   SET PARITY HARDWARE { EVEN, ODD }
+          Unlike SET PARITY { EVEN, ODD, MARK, SPACE }, which selects 7
+          data bits plus the indicated kind of parity (to be done in
+          software by Kermit itself), SET PARITY HARDWARE selects 8 data
+          bits plus even or odd parity, to be done by the underlying
+          hardware, operating system, or device driver. This command is
+          effective only with a SET LINE or SET PORT device. That is, it
+          has no effect in remote mode, nor on network connections. There
+          is presently no method for selecting 8 data bits plus mark or
+          space parity. If hardware parity is in effect, the variable
+          \v(hwparity) is set to "even" or "odd". Note: some platforms
+          might also support settings of SPACE, MARK, or NONE.
+
+   SET STOP-BITS { 1, 2 }
+          This tells the number of 1-bits to insert after an outbound
+          character's data and parity bits, to separate it from the next
+          character. Normally 1. Choosing 2 stop bits should do no harm,
+          but will slow down serial transmission by approximately 10
+          percent. Historically, 2 stop bits were used with Teletypes (at
+          110 bps or below) for print-head recovery time. There is
+          presently no method for choosing any number of stop bits
+          besides 1 and 2.
+
+   SET SERIAL [ dps ]
+          dps stands for Data-bits, Parity, Stop-bits. This is the
+          notation familiar to many people for serial port configuration:
+          7E1, 8N1, 7O2, etc. The data bits number also becomes the
+          TERMINAL BYTESIZE setting. The second character is E for Even,
+          O for Odd, M for Mark, S for Space, or N for None. The list of
+          available options depends on the capabilities of the specific
+          platform. If dps is omitted, 8N1 is used. Type "set serial ?"
+          for a list of available choices. Examples:
+
+        SET SERIAL 7E1
+                Equivalent to SET PARITY EVEN, SET STOP-BITS 1, SET TERM
+                BYTE 7.
+
+        SET SERIAL 8N1
+                Equivalent to SET PARITY NONE, SET STOP-BITS 1, SET TERM
+                BYTE 8.
+
+        SET SERIAL 7E2
+                Equivalent to SET PARITY EVEN and SET STOP-BITS 2, SET
+                TERM BYTE 7.
+
+        SET SERIAL 8E2
+                Same as SET PARITY HARDWARE EVEN, SET STOP-BITS 2, SET
+                TERM BYTE 8.
+
+        SET SERIAL
+                Same as SET PARITY NONE and SET STOP-BITS 1, SET TERM
+                BYTE 8.
+
+   Notes:
+
+     * The SET SERIAL xx2 options are available only in Kermit versions
+       where the SET PARITY HARDWARE command is also available. (SHOW
+       FEATURES includes "HWPARITY" in its options list.)
+     * The SET SERIAL 7xx and 8N1 options affect the software parity
+       setting, even for network connections.
+     * As noted in the manual, selecting 8 data bits does not give you
+       8-bit terminal sessions in CONNECT mode unless you also SET
+       TERMINAL BYTESIZE 8. The default terminal bytesize remains 7, to
+       protect against the situation where the remote host is generating
+       parity but you don't know about it. If the terminal bytesize was 8
+       by default and you CONNECTed to such a host, you would see only
+       garbage on your screen.
+     * If you do not give a SET STOP-BITS or SET SET SERIAL command,
+       C-Kermit does not attempt to set the device's stop bits; instead,
+       it uses whatever setting the device uses when not given explicit
+       instructions about stop bits.
+
+   SHOW COMMUNICATIONS displays the current settings. Stop bits and
+   hardware parity are shown only for SET PORT / SET LINE (serial)
+   devices, since they do not apply to network connections or to remote
+   mode. STOP-BITS is shown as "(default)" if you have not given an
+   explicit SET STOP-BITS or SET SERIAL command.
+
+   The \v(serial) variable shows the SET SERIAL setting (8N1, 7E1, etc).
+     _________________________________________________________________
+
+  2.11. Getting Access to the Dialout Device
+
+     This section is for UNIX only; note the special words about QNX at
+     the end. Also see [418]Section 2.0 for SET LINE switches,
+     particularly the /SHARE switch for VMS only.
+
+   C-Kermit does its best to obey the UUCP lockfile conventions of each
+   platform (machine, operating system, OS version) where it runs, if
+   that platform uses UUCP.
+
+   But simply obeying the conventions is often not good enough, due to
+   the increasing likelihood that a particular serial device might have
+   more than one name (e.g. /dev/tty00 and /dev/term/00 are the same
+   device in Unixware 7; /dev/cua and /dev/cufa are the same device in
+   NeXTSTEP), plus the increasingly widespread use of symlinks for device
+   names, such as /dev/modem.
+
+   C-Kermit 7.0 goes to greater lengths than previous versions to
+   successfully interlock with other communications program (and other
+   instances of Kermit itself); for example, by:
+
+     * Creation of dual lockfiles whenever a symlink is used; one for the
+       link name and one for the real name.
+     * Creation of dual lockfiles in HP-UX according to HP rules.
+     * Creation of dual uppercase/lowercase lockfile names in SCO
+       UNIX/ODT/OSR5.
+     * The use of ttylock() in versions of AIX where it works.
+     * The use, wherever possible, of lockfile names based on
+       inode/major/minor device number rather than device name.
+
+   See the [419]ckuins.txt and [420]ckubwr.txt files for details.
+
+   QNX is almost unique among UNIX varieties in having no UUCP programs
+   nor UUCP-oriented dialout-device locking conventions. QNX does,
+   however, allow a program to get the device open count. This can not be
+   a reliable form of locking unless all applications do it (and they
+   don't), so by default, Kermit uses this information only for printing
+   a warning message such as:
+
+  C-Kermit>set line /dev/ser1
+  WARNING - "/dev/ser1" looks busy...
+
+   However, if you want to use it as a lock, you can do so with:
+
+  SET QNX-PORT-LOCK { ON, OFF }
+
+   QNX-PORT-LOCK is OFF by default; if you set in ON, C-Kermit fails to
+   open any dialout device when its open count indicates that another
+   process has it open. SHOW COMM (in QNX only) displays the setting, and
+   if you have a port open, it also shows the current open count (with
+   C-Kermit's own access always counting as 1).
+     _________________________________________________________________
+
+  2.12. The Connection Log
+
+   C-Kermit 7.0 adds the ability to log connections, so you can see where
+   you've been and have a record of calls you've made. A connection is
+   defined as any communications session that is begun by SET LINE, SET
+   PORT, DIAL, SET HOST, TELNET, or RLOGIN. Connections are not logged
+   unless you request it; the command is:
+
+   LOG CX [ filename [ { NEW, APPEND } ] ]
+          Enables logging of connections in the given file. If the
+          trailing { NEW, APPEND } keyword is omitted, the file is opened
+          for appending; i.e. new records are written to the end. If NEW
+          is specified, a new file is created; if a file of the same name
+          already existed, it is overwritten. If the filename is omitted,
+          CX.LOG in your home (login) directory is used (note:
+          uppercase). To accept all defaults, just use "log connections"
+          (or "l c" for short). Synonym: LOG CONNECTIONS.
+
+   CLOSE CX-LOG
+          This closes the connection log if it was open. (Note, the CLOSE
+          CONNECTION command closes the connection itself).
+
+   SHOW CX
+          This shows your current connection, if any, including the
+          elapsed time (since you opened it). Synonym: SHOW CONNECTION.
+
+   \v(cx_time)
+          This variable shows the elapsed time of your current
+          connection, or if there is no current connection, of your most
+          recent connection, of if there have been no connections, 0.
+
+   The connection contains one line per connection, of the form:
+
+  yyyymmdd hh:mm:ss username pid p=v [ p=v [ ... ] ]
+
+   where the timestamp (in columns 1-18) shows when the connection was
+   made; username is the login identity of the person who made the
+   connection; pid is Kermit's process ID when it made the connection.
+   The p's are parameters that depend on the type of connection, and the
+   v's are their values:
+
+  T = Connection Type (TCP, SERIAL, DIAL, DECNET, etc).
+  H = The name of the Host from which the connection was made.
+  N = Destination phone Number or Network host name or address.
+  D = Serial connections only: Device name.
+  O = Dialed calls only: Originating country code & area code if known.
+  E = Elapsed time in hh:mm:ss format (or hhh:mm:ss, etc).
+
+   If you always want to keep a connection log, simply add:
+
+  log connections
+
+   to your C-Kermit customization file. Note, however, that if you make a
+   lot of connections, your CX.LOG will grow and grow. You can handle
+   this by adding a "logrotate" procedure like the following to your
+   customization file, before the "log connections" command:
+
+  define LOGROTATE {                    ; Define LOGROTATE macro
+      local \%i \%m \%d \%n \%f MAX
+      def MAX 4                         ; How many months to keep
+      if not def \%1 -                  ; No argument given
+        end 1 \%0: No filename given
+      if not = 1 \ffiles(\%1) -         ; Exactly 1 file must match
+        end 1 \%0: \%1 - File not found
+      .\%d := \fsubstr(\fdate(\%1),1,6) ; Arg OK - get file year & month
+      if = \%d -                        ; Compare file year & month
+        \fsubstr(\v(ndate),1,6) -       ; with current year & month
+          end 0                         ; Same year & month - done
+      rename \%1 \%1.\%d                ; Different - rename file
+      .\%n := \ffiles(\%1.*)            ; How many old files
+      if < \%n \m(MAX) end 0            ; Not enough to rotate
+      .\%m := \%1.999999                ; Initial compare string
+      for \%i 1 \%n 1 {                 ; Loop thru old logs
+         .\%f := \fnextfile()           ; Get next file name
+         if llt \%f \%m .\%m := \%f     ; If this one older remember it
+      }
+      delete \%m                        ; Delete the oldest one
+  }
+  log connections                       ; Now open the (possibly new) log
+  logrotate \v(home)CX.LOG              ; Run the LOGROTATE macro
+
+   As you can see, this compares the yyyymm portion of the modification
+   date (\fdate()) of the given file (\%1) with the current yyyymm. If
+   they differ, the current file has the yyyymm suffix (from its most
+   recent modification date) appended to its name. Then we search through
+   all other such files, find the oldest one, and delete it. Thus the
+   current log, plus the logs from the most recent four months, are kept.
+   This is all done automatically every time you start C-Kermit.
+
+   On multiuser systems, it is possible to keep a single, shared,
+   system-wide connection log, but this is not recommended since (a) it
+   requires you keep a publicly write-accessible logfile (a glaring
+   target for mischief), and (b) it would require each user to log to
+   that file and not disable logging. A better method for logging
+   connections, in UNIX at least, is syslogging (see [421]ckuins.txt
+   Section 15 and [422]Section 4.2 of the [423]IKSD Administration Guide
+   for details).
+     _________________________________________________________________
+
+  2.13. Automatic Connection-Specific Flow Control Selection
+
+   Beginning in C-Kermit 7.0, the appropriate flow-control method for
+   each connection type is kept in a table, for example:
+
+  Remote:           NONE
+  Modem:            RTS/CTS
+  Direct-Serial:    NONE
+  TCPIP:            NONE
+
+   The size of the table and values for each connection type can vary
+   from platform to platform. Type "set flow ?" for a list of available
+   flow-control types.
+
+   The table is used to automatically select the appropriate kind of flow
+   control whenever you make a connection. You can display the table
+   with:
+
+  SHOW FLOW-CONTROL
+
+   The defaults are as follows:
+
+   Remote:
+          NONE or XON/XOFF. This is because C-Kermit is not allowed to
+          find out what type of connection the incoming user has (*). No
+          kind of flow control will work on every kind of connection,
+          including (unexpectedly) KEEP, which we would have liked to
+          use, but not turning off flow control at the remote end during
+          file transfer on TCP/IP connections is fatal to the transfer
+          (except in VMS and HP-UX, where it must be set to Xon/Xoff!)
+          Therefore if you are dialing in to a serial port on a server
+          (UNIX or VMS) where C-Kermit is running, you will need to tell
+          C-Kermit to "set flow keep" before transferring files (assuming
+          the modem and port are configured correctly by the system
+          administrator; otherwise you'll need to give a specific kind of
+          flow control, e.g. "set flow xon/xoff"), so in this case
+          C-Kermit will not disable flow control, as it must do when you
+          are coming via Telnet (directly or through a terminal server,
+          except on VMS and HP-UX).
+
+   Modem:
+          This applies when you dial out with a modem. In this case, the
+          MODEM FLOW-CONTROL setting takes affect after the SET FLOW
+          setting, so it can pick the most appropriate flow control for
+          the combination of the particular modem and the
+          computer/port/driver that is dialing.
+
+   Direct-Serial:
+          The default here is NONE because C-Kermit has no way of knowing
+          what kind of flow control, if any, is or can be done by the
+          device at the other end of the connection. RTS/CTS would be a
+          bad choice here, because if the CTS signal is not asserted, the
+          connection will hang. And since direct connections are often
+          made with 3-wire cables, there is a good chance the CTS signal
+          will not be received.
+
+   TCPIP:
+          NONE, since TCP and IP provide their own flow control
+          transparently to the application, except in VMS, where Xon/Xoff
+          is the default due to the requirements of the VMS TCP/IP
+          products.
+
+   Other networks:
+          NONE, since networks should provide their flow control
+          transparently to the application.
+
+   (*) This is possibly the worst feature of UNIX, VMS, and other
+   platforms where C-Kermit runs. If C-Kermit was able to ask the
+   operating system what kind of connection it had to the user, it could
+   set up many things for you automatically.
+
+   You can modify the default-flow-control table with:
+
+  SET FLOW-CONTROL /xxx { NONE, KEEP, RTS/CTS, XON/XOFF, ... }
+
+   where "xxx" is the connection type, e.g.
+
+  SET FLOW /REMOTE NONE
+  SET FLOW /DIRECT RTS/CTS
+
+   If you leave out the switch, SET FLOW works as before, choosing the
+   flow control method to be used on the current connection:
+
+  SET FLOW XON/XOFF
+
+   Thus, whenever you make a connection with SET PORT, SET LINE, DIAL,
+   SET HOST, TELNET, RLOGIN, etc, an appropriate form of flow control is
+   selected automatically. You can override the automatic selection with
+   a subsequent SET FLOW command, such as SET FLOW NONE (no switch
+   included).
+
+   The flow control is changed automatically too when you give a SET
+   MODEM TYPE command. For example, suppose your operating system (say
+   Linux) supports hardware flow control (RTS/CTS). Now suppose you give
+   the following commands:
+
+  set line /dev/ttyS2    ; Automatically sets flow to NONE
+  set modem type usr     ; Automatically sets flow to RTS/CTS
+  set modem type rolm    ; Doesn't support RTS/CTS so now flow is XON/XOFF
+
+   IMPORTANT: This new feature tends to make the order of SET LINE/HOST
+   and SET FLOW commands matter, where it didn't before. For example, in
+   VMS:
+
+  SET FLOW KEEP
+  SET LINE TTA0:
+
+   the SET LINE undoes the SET FLOW KEEP command; the sequence now must
+   be:
+
+  SET FLOW /DIRECT KEEP
+  SET LINE TTA0:
+
+   or:
+
+  SET LINE TTA0:
+  SET FLOW KEEP
+     _________________________________________________________________
+
+  2.14. Trapping Connection Establishment and Loss
+
+   If you define a macro called ON_OPEN, it is executed any time that a
+   SET LINE, SET PORT, SET HOST, TELNET, RLOGIN or similar command
+   succeeds in opening a connection. The argument is the host or device
+   name (as shown by SHOW COMMUNICATIONS, and the same as \v(line)). This
+   macro can be used for all sorts of things, like automatically setting
+   connection- or host-specific parameters when the connection is opened.
+   Example:
+
+  def ON_OPEN {
+      switch \%1 {
+        :abccorp.com, set reliable off, break
+        :xyzcorp.com, set receive packet-length 1000, break
+        etc etc...
+      }
+  }
+
+   If you define a macro called ON_CLOSE, it will be executed any time
+   that a SET LINE, SET PORT, SET HOST, TELNET, RLOGIN or any other kind
+   of connection that C-Kermit has made is closed, either by the remote
+   or by a local CLOSE, HANGUP, or EXIT command or other local action,
+   such as when a new connection is opened before an old one was
+   explicitly closed.
+
+   As soon as C-Kermit notices the connection has been closed, the
+   ON_CLOSE macro is invoked at (a) the top of the command parsing loop,
+   or (b) when a connection is closed implicitly by a command such as SET
+   LINE that closes any open connection prior to making a new connection,
+   or (c) when C-Kermit closes an open connection in the act of exiting.
+
+   The ON_CLOSE macro was inspired by the neverending quest to unite
+   Kermit and SSH. In this case using the "tunnel" mechanism:
+
+  def TUNNEL {                                ; \%1 = host to tunnel to
+      local \%p
+      if not def \%1 stop 1
+      assign tunnelhost \%1                   ; Make global copy
+      undef on_close
+      set macro error off
+      close connection                        ; Ignore any error
+      open !read tunnel start \%1
+      read \%p                                ; Get port number
+      if fail stop 1 Tunnel failure: \%1
+      close read
+      if fail stop 1 Tunnel failure: \%1      ; See [424]Section 4.2.8.1
+      assign on_close {                       ; Set up close handler
+          echo Closing tunnel: \m(tunnelhost)
+          !tunnel stop \m(tunnelhost)
+          undef on_close
+      }
+      set host localhost:\%p /telnet
+      if success end 0
+      undef on_close
+      stop 1 Connection failure: \%1
+  }
+
+   In this case, when the connection stops, we also need to shut down the
+   tunnel, even if it is at a later time after TUNNEL has finished
+   executing. This way we can escape back, reconnect, transfer files, and
+   so on until the connection is broken by logging out from the remote,
+   or by explicitly closing it, or by EXITing from C-Kermit, at which
+   time the tunnel is shut down.
+
+   When the connection is closed, no matter how, the ON_CLOSE macro
+   executes and then undefines (destroys) itself, since we don't want to
+   be closing tunnels in the future when we close subsequent connections.
+
+   Other such tricks can be imagined, including ending ON_CLOSE with a
+   STOP command to force the command stack to be peeled all the way back
+   to the top, for example in a deeply nested script that depends on the
+   connection being open:
+
+  def on_close { stop 1 CONNECTION LOST }
+
+   When C-Kermit invokes the ON_CLOSE macro, it supplies one argument
+   (\%1): the reason the connection was closed as a number, one of the
+   following:
+
+  2 - Fatal failure to negotiate a required item on a network connection.
+  1 - Closed by C-Kermit command.
+  0 - All others (normally closed by remote).
+
+   which may be used for any purpose; for example, to add a comment to
+   the connection log:
+
+  def on_close {
+      local \%m
+      if not open cx end 0
+      switch \%1 {
+        :0, .\%m = Closed by remote, break
+        :1, .\%m = Closed by me, break
+        :2, .\%m = Network protocol negotiation failure, break
+      }
+      if def \%m writeln cx {# \%m}
+  }
+     _________________________________________________________________
+
+  2.15. Contacting Web Servers with the HTTP Command
+
+   C-Kermit 7.0 (at this writing, the UNIX version only) supports direct
+   contact and interaction with Web servers via HTTP 1.0 protocol. To
+   make a connection, use Kermit's normal method for making a TCP/IP
+   connection, but specify the HTTP port:
+
+  SET HOST host http [ switches ]
+
+   where host is the IP hostname or address, and http is the name of the
+   TCP port for the Web server. Relevant switches include:
+
+   /RAW
+          Treat the connection as a transparent binary pipe. This switch
+          may be required if a port other than 'http' is used.
+
+   /SSL
+          Make an secure private connection with SSL (only if SSL support
+          is included in your version of Kermit). In this case the port
+          name might need to be https rather than http, e.g. "set host
+          secureserver.xyxcorp.com https /ssl".
+
+   /TLS
+          Make an secure private connection with TLS (only if TLS support
+          is included in your version of Kermit). In this case the port
+          name would be https rather than http.
+
+   Then you can issue an HTTP command. In most cases, the server closes
+   the connection when the command is complete. Example:
+
+  SET HOST www.columbia.edu http
+  IF FAIL EXIT 1 Can't contact server
+  HTTP GET kermit/index.html
+
+   At this point the connection is closed, since that's how HTTP 1.0
+   works. If you want to perform additional operations, you must
+   establish a new connection with another SET HOST command.
+
+   The HTTP command acts as a client to the Web server, except instead of
+   displaying the results like a Web browser would, it stores them. Any
+   HTTP command can (but need not) include any or all of the following
+   switches:
+
+   /AGENT:user-agent
+          Identifies the client to the server; "C-Kermit" or "Kermit-95"
+          by default.
+
+   /HEADER:header-line
+          Used for specifying any optional headers. A list of headers is
+          provided using braces for grouping:
+
+  /HEADER:{{tag:value}{tag:value}...}
+
+          For a listing of valid tag value and value formats see [425]RFC
+          1945: Hypertext Transfer Protocol -- HTTP/1.0. A maximum of
+          eight headers may be specified.
+
+   /USER:name
+          In case a page requires a username for access.
+
+   /PASSWORD:password
+          In case a page requires a password for access.
+
+   /ARRAY:arrayname
+          Tells Kermit to store the response headers in the given array,
+          one line per element. The array need not be declared in
+          advance. Example:
+
+  C-Kermit? http /array:c get kermit/index.html
+  C-Kermit? 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.
+
+   The HTTP commands are:
+
+   HTTP [ switches ] GET remote-filename [ local-filename ]
+          Retrieves the named file. If a local-filename is given, the
+          file is stored locally under that name; otherwise it is stored
+          with its own name.
+
+   HTTP [ switches ] HEAD remote-filename local-filename
+          Like GET except without actually getting the file; instead it
+          gets only the headers, storing them into the given file, whose
+          name must be given, one line per header item, as shown above in
+          the /ARRAY: switch description.
+
+   HTTP [ switches ] INDEX remote-directory [ local-filename ]
+          Retrieves the file listing for the given server directory.
+          NOTE: This command is not supported by most Web servers.
+
+   HTTP [ switches ] POST [ /MIME-TYPE:type ] local-file remote-file
+          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 [ switches ] PUT [ /MIME-TYPE:type ] local-file remote-file
+          Uploads a local file to a server file.
+
+   HTTP [ switches ] DELETE remote-filename
+          Instructs the server to delete the specified filename.
+     _________________________________________________________________
+
+  3. TERMINAL CONNECTION
+
+  3.1. CONNECT Command Switches
+
+   The following switches (see [426]Section 1.5) were added to the
+   CONNECT command in 7.0:
+
+   /QUIETLY
+          Don't print the "Connecting to..." or "Back at..." messages. CQ
+          is an invisible command synonym for CONNECT /QUIETLY.
+
+   /TRIGGER:string
+          Specify a trigger or triggers ([427]Section 3.2) effective for
+          this CONNECT command only, temporarily overriding any current
+          SET TERMINAL TRIGGER values ([428]Section 3.2).
+
+   Note: Other switches might also be available; type "connect ?" for a
+   list, "help connect" for a description of each.
+     _________________________________________________________________
+
+  3.2. Triggers
+
+   Triggers were added for UNIX, VMS, AOS/VS, and K95 in C-Kermit 7.0.
+
+   SET TERMINAL TRIGGER string
+          Tells C-Kermit to look for the given string during all
+          subsequent CONNECT sessions, and if seen, to return to command
+          mode automatically, as if you had escaped back manually. If the
+          string includes any spaces, you must enclose it in braces.
+          Example:
+
+  set terminal trigger {NO CARRIER}
+
+   Comparisons are made after character-set translation.
+
+   If a string is to include a literal brace character, precede it with a
+   backslash:
+
+  ; My modem always makes this noise when the connection is lost:
+  set terminal trigger |||ppp\{\{\{\{UUUUUUU
+
+   If you want Kermit to look for more than one string simultaneously,
+   use the following syntax:
+
+  set terminal trigger {{string1}{string2}...{stringn}}
+
+   In this case, C-Kermit will return to command mode automatically if
+   any of the given strings is encountered. Up to 8 strings may be
+   specified.
+
+   If the most recent return to command mode was caused by a trigger, the
+   new variable, \v(trigger), shows the trigger value; otherwise
+   \v(trigger) is empty.
+
+   The SHOW TRIGGER command displays the SET TERMINAL TRIGGER values as
+   well as the \v(trigger) value.
+     _________________________________________________________________
+
+  3.3. Transparent Printing
+
+   As noted in the manual, C-Kermit's CONNECT command on UNIX is not a
+   terminal emulator, but rather a "semitransparent pipe" between the
+   terminal or emulator you are using to access C-Kermit, and the remote
+   host to which C-Kermit is connected. The "semitransparent" qualifier
+   is because of character-set translation as well as several actions
+   taken by the emulator in response to the characters or strings that
+   pass through it, such as APCs, Kermit packets (autodownload),
+   triggers, etc.
+
+   The UNIX version of C-Kermit 7.0 adds another such action: Transparent
+   printing, also called Controller printing (as distinct from Autoprint
+   or line or screen print). It is intended mainly for use on UNIX
+   workstation consoles (as opposed to remote logins), but with some care
+   can also be used when accessing C-Kermit remotely.
+
+   Transparent printing is related to APC by sharing C-Kermit's built-in
+   ANSI escape-sequence parser to detect "printer on" and "printer off"
+   sequences from the host. When the printer-on sequence is received, all
+   subsequent arriving characters -- including NUL, control characters,
+   and escape sequences -- are sent to the SET PRINTER device instead of
+   to your screen until the printer-off sequence is received, or you
+   escape back, whichever happens first. These bytes are not translated
+   or modified or filtered in any way by Kermit (except for possibly
+   stripping of the 8th bit, as noted below), but if filtering or
+   translation is desired, this can be accomplished by your SET PRINTER
+   selection (e.g. by choosing a pipeline of filters).
+
+   By default, your SET PRINTER device is your default UNIX printer, but
+   it can also be a file, a command, or the null device (which causes all
+   printer material to be discarded). See [429]Using C-Kermit, 2nd Ed.,
+   p.41 for details.
+
+   Transparent printing is controlled by the command:
+
+   SET TERMINAL PRINT { ON, OFF }
+          When ON, transparent-print sequences are obeyed, and printing
+          occurs on the system where C-Kermit is running. When OFF,
+          transparent print sequences are ignored and passed through to
+          your actual terminal or emulator, along with the data they
+          enclose. OFF is the default, for compatibility with earlier
+          C-Kermit releases. As noted in the manual, when the current SET
+          PRINTER device is a file, transparent-print material is
+          appended to it; the file is not overwritten.
+
+   SET TERMINAL BYTESIZE { 7, 8 }
+   SET PARITY { EVEN, ODD, MARK, SPACE, NONE }
+          If the terminal bytesize is 7, or PARITY is not NONE, the 8th
+          bit of each byte is stripped prior to printing.
+
+   The transparent-print escape sequences are:
+
+   <ESC>[5i
+          Printer On. Send all subsequent incoming bytes to the printer
+          without any kind of filtering, translation, or alteration.
+          Note: <ESC> stands for ASCII character number 27 (decimal),
+          Escape.
+
+   <ESC>[4i
+          Printer Off. Resume displaying incoming bytes on the screen.
+
+   These are the same sequences used by DEC VT100 and higher terminals
+   and other ANSI X3.64 and ISO 6429 compatible terminals. There is no
+   provision for selecting other printer-control sequences.
+
+   Restrictions:
+
+    1. You must SET TERM TRANSPARENT-PRINT ON before you can use this
+       feature.
+    2. Only the 7-bit forms of the escape sequences are supported. The
+       8-bit CSI C1 control is not recognized.
+    3. Autoprint is not supported, since this requires a full-fledged
+       terminal emulator with direct access to the screen.
+    4. The start-print and stop-print sequences pass through to the
+       screen (there is no way to avoid this without causing unacceptable
+       delays or deadlocks in CONNECT mode). Thus if your terminal or
+       emulator also supports transparent printing via these same
+       sequences, an empty file will be sent to its printer. Normally
+       this has no effect.
+
+   Point (4) is similar to the situation with autodownload and APC --
+   when you have several Kermit clients in a chain, you should take care
+   that these features are enabled in only one of them.
+
+   Example 1:
+
+  set printer {|lpr -Plaser}  ; Specify the printer (if not default).
+  set term print on           ; Enable transparent printing.
+  set term byte 8             ; Enable 8-bit characters.
+  connect                     ; Enter CONNECT mode.
+
+   Example 2:
+
+  set printer /home/users/olga/printer.log  ; Send printer material to a file.
+
+   Example 3:
+
+  set printer {| grep -v ^Received | lpr}   ; Filter out some lines
+
+   Then use "pcprint" or "vtprint" commands on the host to initiate
+   transparent print operations. See [430]Using C-Kermit, 2nd Ed., p.406
+   for details.
+
+   Here is a sample "pcprint" shell script for UNIX:
+
+  #!/bin/sh
+  echo -n '<ESC>[5i'
+  if [ $# -eq 0 ]; then
+    cat
+  else
+    cat $*
+  fi
+  echo -n '<FF><ESC>[4i'
+  # (end)
+
+   (Replace "<ESC>" by the actual ASCII Escape character and "<FF>" by
+   the ASCII Formfeed character).
+
+   If you always want transparent printing enabled, put "set term print
+   on" in your C-Kermit customization file (~/.mykermrc in UNIX). The
+   "set term bytesize" selection, however, is a property of each separate
+   connection.
+     _________________________________________________________________
+
+  3.4. Binary and Text Session Logs
+
+   C-Kermit 7.0 corrects an oversight in earlier releases, in which
+   binary session logs (SET SESSION-LOG BINARY) translated character sets
+   and performed various formatting transformations (e.g. "newline mode")
+   before writing characters to the session log. In C-Kermit 7.0,
+   binary-mode session logging writes characters as they come in, before
+   anything (other that parity-bit stripping) is done to them. Text-mode
+   session logging records the characters after processing.
+     _________________________________________________________________
+
+  4. FILE TRANSFER
+
+   Every file is transferred either in text mode (which implies
+   record-format and character-set translation) or binary mode (in which
+   each byte is sent literally without any kind of conversion). The mode
+   in which a file is transferred is controlled by (a) the default mode,
+   in the absence of any other indications; (b) the SET FILE TYPE
+   command; (c) various automatic mechanisms based on client/server
+   negotiations, directory information or filename patterns, etc.
+
+   The default FILE TYPE was changed from TEXT to BINARY in C-Kermit 7.0
+   because:
+
+     * Transferring a text file in binary mode does less damage than
+       transferring a binary file in text mode.
+     * Only binary-mode transfers can be recovered from the point of
+       failure.
+     * The automatic transfer-mode mechanisms switch to text mode on a
+       per-file basis anyway, so only those files that are not covered by
+       the automatic mechanisms are affected.
+     * All file transfers on the Web are done in binary mode, so people
+       are accustomed to it and expect it.
+     _________________________________________________________________
+
+  4.0. BUG FIXES, MINOR CHANGES, AND CLARIFICATIONS
+
+    4.0.0. Filenames with Spaces
+
+   Filenames that contain spaces are a major nuisance to a program like
+   Kermit, whose command language is line- and word-oriented, in which
+   words are separated by spaces and a filename is assumed to be a
+   "word". In general (unless noted otherwise in the description of a
+   particular command), there is only one way to refer to such files in
+   Kermit commands, and that is to enclose the name in braces:
+
+  send {this file}
+
+   Tells Kermit to send the file whose name is "this file" (two words, no
+   quotes). Of course, various circumlocutions are also possible, such
+   as:
+
+  define \%a this file
+  send \%a
+
+   BUT, perhaps contrary to expectation, you can't use "\32" to represent
+   the space:
+
+  send this\32file
+
+   does not work. Why? Because the Kermit parser, which must work on many
+   operating systems including Windows, has no way of knowing what you
+   mean by "this\32file". Do you mean a file whose name is "this file" in
+   the current directory? Or do you mean a file whose name is "32file" in
+   the "this" subdirectory of the current directory? Guessing won't do
+   here; Kermit must behave consistently and deterministically in all
+   cases on all platforms.
+
+   Note that you can't use Esc or Tab within {...} for filename
+   completion, or question mark to get a filename list. However, you can
+   include wildcards; for example:
+
+  send {* *}
+
+   sends all files whose name contains a space.
+
+   All things considered, it is best to avoid spaces in file and
+   directory names if you can. Also see [431]Section 5.4 on this topic.
+     _________________________________________________________________
+
+    4.0.1. Packet out of Window
+
+   C-Kermit 6.0 could send packets "out of window" if the window size was
+   greater than 1 and ACKs had arrived out of order. Fixed in 6.1.
+     _________________________________________________________________
+
+    4.0.2. MOVE after ADD SEND-LIST
+
+   ADD SEND-LIST followed by MOVE did not delete original files; fixed in
+   6.1. Carrier loss was not detected during transfer; in 7.0 C-Kermit
+   checks for this (but results can not be guaranteed). In any case, the
+   protocol will eventually time out if the connection is lost.
+     _________________________________________________________________
+
+    4.0.3. GET and RECEIVE As-Names
+
+   In 5A(190) through 6.0.192, the GET and RECEIVE as-name did not
+   properly override the RECEIVE PATHNAMES setting. In 7.0 it does.
+     _________________________________________________________________
+
+    4.0.4. New Brief Statistics Listing
+
+   Version 7.0 adds a /BRIEF switch to the STATISTICS command, to display
+   a short file-transfer statistics report. /BRIEF is now the default.
+   Use /VERBOSE to see the full display, which is about 25 lines long.
+     _________________________________________________________________
+
+    4.0.5. Improved FAST Command
+
+   The preinstalled definition of the FAST macro did not take enough
+   factors into account. Now it sets packet lengths and window sizes
+   appropriate to the configuration. Furthermore, in IRIX only, it might
+   restrict the SEND packet length to 4000, to work around a bug in the
+   IRIX Telnet server, depending on the IRIX version (see
+   [432]ckubwr.txt, IRIX section). To see the built-in definition of the
+   FAST macro, type "show macro fast". To change it, simply define it to
+   be whatever you want -- it's just a macro, like any other.
+     _________________________________________________________________
+
+    4.0.6. The SET SEND BACKUP Command
+
+   Version 7.0 adds SET SEND BACKUP { ON, OFF }. This tells whether
+   backup files should be sent. Backup files are the ones created by
+   Kermit (and EMACS, and possibly other applications) to preserve old
+   copies of files when creating new ones with the same name. Kermit does
+   this when receiving a file and its FILE COLLISION setting is BACKUP
+   (or RENAME, in which case it the new file gets the backup name). On
+   most platforms, the backup name is formed by adding:
+
+  .~n~
+
+   to the end of the filename, where "n" is a number. For example, if the
+   original file is oofa.txt, a backup file might be called:
+
+  oofa.txt.~1~
+
+   (or oofa.txt.~2~, etc). If you SET SEND BACKUP OFF, this tells Kermit
+   not to send files that have backup names. Normally, SET SEND BACKUP is
+   ON (as shown by SHOW PROTOCOL), and backup files are sent if their
+   names match the SEND file specification.
+
+   Also see PURGE, SET FILE COLLISION, SEND /NOBACKUP, DIRECTORY
+   /[NO]BACKUP.
+     _________________________________________________________________
+
+    4.0.7. The SET { SEND, RECEIVE } VERSION-NUMBERS Command
+
+   VMS Only. Normally when sending files, VMS C-Kermit strips the version
+   number. For example, if the file is FOO.BAR;34, the name is sent as
+   FOO.BAR (without the ";34"). If you want to keep version numbers on
+   when sending files, use SET SEND VERSION-NUMBERS ON. The effect
+   depends on the receiver.
+
+   Normally when receiving files, and an incoming filename includes a
+   VMS-style version number (such as FOO.BAR;34) VMS C-Kermit strips it
+   before trying to create the new file; this way the new file receives
+   the next highest version number in the customary manner for VMS. If
+   you want version numbers on incoming filenames to be used in creating
+   the new files, use SET RECEIVE VERSION-NUMBERS ON.
+
+   Normally these commands would be effective only when VMS C-Kermit is
+   exchanging files with a non-VMS Kermit program, since VMS-to-VMS
+   transfers use labeled mode unless you have gone out of your way to
+   defeat it.
+
+   Example: You want to send all versions of all files in the current
+   directory from a VMS C-Kermit client to a UNIX C-Kermit server. Use:
+
+  set send version-numbers on
+  send *.*;*
+
+   The resulting Unix files will have VMS-style version numbers as part
+   of their name, for example "foo.bar;1", "foo.bar;2", etc.
+
+   Now suppose you want to send these files from Unix to another VMS
+   system and preserve the version numbers. Again we have a Unix C-Kermit
+   server and VMS C-Kermit client. Give these commands to the client:
+
+  set receive version-numbers on
+  get *
+     _________________________________________________________________
+
+    4.0.8. The SET { SEND, RECEIVE } { MOVE-TO, RENAME-TO } Commands
+
+   These commands are persistent global versions of the /MOVE-TO: and
+   /RENAME-TO: switches of the SEND, GET, and RECEIVE commands. They
+   should normally be used only when setting up a dedicated
+   transaction-processing application, in which each file is to be moved
+   or renamed immediately after, and only if, it is transferred
+   successfully, so that (for example) an independent, concurrent process
+   can notice when new files appear and process them immediately without
+   having to guess whether they are complete.
+     _________________________________________________________________
+
+    4.0.9. SET FILE INCOMPLETE AUTO
+
+   SET FILE INCOMPLETE { KEEP, DISCARD }, which tells whether to keep or
+   discard incompletely received files, has a new option, AUTO, which is
+   also the default. It means KEEP the incomplete file if the transfer is
+   in binary mode, otherwise DISCARD it. This reduces the chances that a
+   subsequent recovery operation (RESEND, REGET, etc) could produce a
+   corrupt file, since recovery works only for binary-mode transfers.
+     _________________________________________________________________
+
+  4.1. FILE-TRANSFER FILENAME TEMPLATES
+
+   File-transfer filename templates allow files to be renamed
+   automatically by the file sender, the receiver, or both, during
+   transfer of groups of files.
+
+    4.1.1. Templates in the As-Name
+
+   Prior to C-Kermit 6.1 and Kermit 95 1.1.12 the only options that could
+   be used to affect the names of files being transferred were SET
+   FILENAMES { LITERAL, CONVERTED } and SET { SEND, RECEIVE } PATHNAMES {
+   ON, OFF }, plus the "as-name" feature of the SEND (MOVE, etc) and
+   RECEIVE commands.
+
+   Previously, the as-name could be used only for a single file. For
+   example:
+
+  SEND FOO BAR
+
+   would send the file FOO under the name BAR, but:
+
+  SEND *.TXT anything
+
+   was not allowed, since it would give the same name to each file that
+   was sent. When receiving:
+
+  RECEIVE FOO
+
+   would rename the first incoming file to FOO before storing it on the
+   disk, but subsequent files would not be renamed to FOO, since this
+   would result in overwriting the same file repeatedly. Instead, they
+   were stored under the names they arrived with.
+
+   Beginning in C-Kermit 6.1 and Kermit 95 1.1.12, it is possible to
+   specify as-names in SEND, RECEIVE, and related commands even for file
+   groups. This is accomplished by using replacement variables in the
+   as-name, along with optional material such character-string functions
+   and/or constant strings. An as-name containing replacement variables
+   is called a filename template.
+
+   The key to filename templates is the new variable:
+
+  \v(filename)
+
+   During file transfer it is replaced by the name of each file currently
+   being transferred (after transfer, it is the name of the last file
+   transferred).
+
+   So, for example:
+
+  send *.txt \v(filename).new
+
+   sends each file with its own name, but with ".new" appended to it. Of
+   course if the name already contains periods, this could confuse the
+   file receiver, so you can also achieve fancier effects with
+   constructions like:
+
+  send *.txt \freplace(\v(filename),.,_).new
+
+   which replaces all periods in the original filename by underscores,
+   and then appends ".new" to the result. So, for example, oofa.txt would
+   be sent as oofa_txt.new.
+
+   Another new variable that is useful in this regard is \v(filenumber),
+   which is the ordinal number of the current file in the file group, so
+   you can also:
+
+  send *.txt FILE\flpad(\v(filenum),2,0)
+
+   resulting in a series of files called FILE00, FILE01, FILE02, etc. (At
+   the end of the transfer, \v(filenum) tells the number of files that
+   were transferred).
+
+   If you specify a constant as-name when sending a file group:
+
+  send *.txt thisnameonly
+
+   Kermit complains and asks you to include replacement variables in the
+   as-name. You should generally use \v(filename) or \v(filenumber) for
+   this purpose, since other variables (with the possible exception of
+   date/time related variables) do not change from one file to the next.
+   But Kermit accepts any as-name at all that contains any kind of
+   variables for file group, even if the variable will not change. So:
+
+  send *.txt \%a
+
+   is accepted, but all files are sent with the same name (the value of
+   \%a, if it has one and it is constant). If the variable has no value
+   at all, the files are sent under their own names.
+
+   Of course, the value of \%a in the previous example need not be
+   constant:
+
+  define \%a FILE\flpad(\v(filenum),2,0)_at_\v(time)
+  send *.txt \%a
+
+   The RECEIVE command, when given without an as-name, behaves as always,
+   storing all incoming files under the names they arrive with, subject
+   to SET FILE NAME and SET RECEIVE PATHNAMES modifications ([433]Section
+   4.10).
+
+   However, when an as-name is given in the RECEIVE command, it is
+   applied to all incoming files rather than to just the first. If it
+   does not contain replacement variables, then the current FILE
+   COLLISION setting governs the result. For example:
+
+  receive foo
+
+   will result in incoming files named foo, foo.~1~, foo.~2~, and so on,
+   with the default FILE COLLISION setting of BACKUP. If it does contain
+   replacement variables, of course they are used.
+
+   When receiving files, the \v(filename) variable refers to the name
+   that was received in the incoming file-header packet, BEFORE any
+   processing by SET FILE NAMES or SET RECEIVE PATHNAMES. Since the
+   filenames in file-header packets are usually in uppercase, you would
+   need to convert them explicitly if you want them in lowercase, e.g.:
+
+  receive \flower(\v(filename)).new
+     _________________________________________________________________
+
+    4.1.2. Templates on the Command Line
+
+   On the command-line, use templates as shown above as the -a option
+   argument, bearing in mind the propensity of UNIX and perhaps other
+   shells to treat backslash as a shell escape character. So in UNIX (for
+   example):
+
+  kermit -s oofa.* -a x.\\v(filenum)
+
+   By the way, this represents a change from 6.0 and earlier releases in
+   which the as-name (-a argument or otherwise) was not evaluated by the
+   command parser. Thus, for example, in VMS (where the shell does not
+   care about backslashes), it was possible to:
+
+  kermit -s oofa.txt -a c:\tmp\oofa.txt
+
+   Now backslashes in the as-name must be quoted not only for the shell
+   (if necessary) but also for Kermit itself:
+
+  kermit -s oofa.txt -a c:\\tmp\\oofa.txt      ; Kermit only
+  kermit -s oofa.txt -a c:\\\\tmp\\\\oofa.txt  ; Shell and Kermit
+
+   You can also use the \fliteral() function for this:
+
+  kermit -s oofa.txt -a \fliteral(c:\tmp\oofa.txt)      ; Kermit only
+  kermit -s oofa.txt -a \\fliteral(c:\\tmp\\oofa.txt)   ; Shell and Kermit
+     _________________________________________________________________
+
+    4.1.3. Post-Transfer Renaming
+
+   Filename templates are now also useful in SET { SEND, RECEIVE }
+   RENAME-TO and in the /RENAME-TO: switch, that can be given to the
+   SEND, GET, or RECEIVE commands; this is similar to an as-name, but is
+   effective on a per-file basis if and only if the file was transferred
+   successfully.
+
+   MOVE-TO and RENAME-TO address a requirement commonly stated for
+   transaction processing and similar systems. Suppose, for example, a
+   central system "X" accepts connections from multiple clients
+   simultaneously; a process on X waits for a file to appear and then
+   processes the file. This process must have a way of knowing when the
+   file has been completely and successfully transferred before it starts
+   to process it. This can be accomplished easily using C-Kermit's SET {
+   SEND, RECEIVE } { MOVE-TO, RENAME-TO } command or /MOVE-TO: or
+   /RENAME-TO: switches, described in [434]Sections 4.7.1 through
+   [435]4.7.3.
+
+   Here's an example for the client side, in which files to be sent are
+   placed in a certain directory (/usr/olga/tosend in this example) by
+   another process when they are ready to go. This might be in a hospital
+   or big doctor's office, where medical insurance claims are entered at
+   a number of workstations, and then deposited in the "tosend"
+   directory, from which they are sent to a claims clearinghouse. We
+   assume the connection is already made and a Kermit server is on the
+   other end.
+
+  local srcdir findir              ; Declare local (automatic) variables
+  assign srcdir /usr/olga/tosend   ; Local source directory (files to send)
+  assign findir /usr/olga/sent     ; Where to move files after they are sent
+  log transactions                 ; Keep a log of transfers
+  cd \m(srcdir)                    ; Change to the source directory
+  while true {                     ; Loop forever...
+      send /move-to:\m(findir) *   ; Send all files
+      sleep 60                     ; Sleep a minute
+  }                                ; Go back and do it again
+
+   Note how simple this is. Once each file is sent, it is moved so it
+   won't be sent again (you could also use SEND /RENAME-TO: or even SEND
+   /DELETE). If a transfer fails, the file is not moved and so we try
+   again to send it next time around. If there are no files to send, the
+   SEND command does nothing but a message is printed; you can avoid the
+   message by checking first to see if any files are in the directory:
+
+  while true {                     ; Loop forever...
+      if > \ffiles(*) 0 -          ; If there are any files
+        send /move-to:\m(findir) * ; send them.
+      sleep 60                     ; Sleep a minute.
+  }                                ; Go back and do it again.
+
+   It's even simpler on the server side (here again we assume the
+   connection is already in place):
+
+  local rcvdir findir              ; Declare local (automatic) variables
+  assign rcvdir /usr/ivan/tmp      ; Temporary receiving directory
+  assign findir /usr/ivan/new      ; Where to move files after reception
+  log transactions                 ; Keep a log of transfers
+  cd \m(rcvdir)                    ; Change to the source directory
+  set receive move-to \m(findir)   ; Declare move-to directory.
+  server                           ; Enter server mode.
+
+   A separate process (e.g. the medical claim-form decoder) can look for
+   files appearing in the /usr/ivan/new directory and process them with
+   every confidence that they have been completely received.
+
+   Note that the use of MOVE-TO can result in moved files overwriting one
+   another (the application would normally avoid this by assigning each
+   transaction a unique, e.g. based on customer number and claim number).
+   But if filename collisions are a possibility in your application,
+   RENAME-TO might be a better choice; you can use any variables you like
+   in the template to ensure uniqueness of the RENAME-TO filename; for
+   example:
+
+  SET RECEIVE RENAME-TO \v(filename)_\v(ndate)_\v(ntime)_\v(userid)_\v(pid)
+     _________________________________________________________________
+
+  4.2. FILE-TRANSFER PIPES AND FILTERS
+
+    4.2.1. INTRODUCTION
+
+   Beginning in C-Kermit 6.1 and Kermit 95 1.1.12, it is possible to send
+   from a command, or "pipe", as well as from a file, and to receive to a
+   pipe or command. In a typical example, we might want to transfer an
+   entire directory tree from one UNIX system to another (but without
+   using the methods described in [436]Sections 4.3 , [437]4.10,
+   [438]4.11, and [439]4.15). We could do this in multiple steps as
+   follows:
+
+  1. Create a tar archive of the desired directory tree
+  2. Compress the tar archive
+  3. Transfer it in binary mode to the other computer
+  4. Decompress it
+  5. Extract the directory tree from the tar archive
+
+   But this is inconvenient and it requires a temporary file, which might
+   be larger than we have room for.
+
+   The new pipe-transfer feature lets you do such things in a single
+   step, and without intermediate files.
+
+   Additional new features, also discussed here, let you specify pre- and
+   post- processing filters for outbound and incoming files, and give you
+   a way to insert the output from shell or system commands into C-Kermit
+   commands.
+
+   The file-transfer related features are available only with Kermit
+   protocol, not with any external protocols, nor with K95's built-in
+   XYZMODEM protocols (because XYZMODEM recovers from transmission errors
+   by rewinding the source file, and you can't rewind a pipe).
+
+   This section begins by discussing the simple and straightforward use
+   of these features in UNIX, in which pipes and input/output redirection
+   are a fundamental component and therefore "just work", and then goes
+   on to discuss their operation in Windows and OS/2, where matters are
+   much more complicated.
+     _________________________________________________________________
+
+    4.2.1.1. TERMINOLOGY
+
+   Standard Input
+          This is a precise technical term denoting the normal source of
+          input for a command or program, which is the keyboard of your
+          terminal by default, but which can be redirected to a file or
+          pipe.
+
+   Stdin
+          Abbreviation for Standard Input.
+
+   Standard Output
+          A precise technical term denoting the normal destination for
+          output from a command or program, which is your terminal screen
+          by default, but which can be redirected to a file.
+
+   Stdout
+          Abbreviation for Standard Output.
+
+   Stdio
+          Abbreviation for Standard Input / Standard Output.
+
+   I/O
+          Abbreviation for Input / Output.
+
+   Shell
+          Text-based system command processor, such as the UNIX shell,
+          DOS COMMAND.COM, etc.
+
+   Pipe
+          A mechanism by which the standard output of one program is sent
+          to the standard input of another.
+
+   Pipeline
+          A series of programs connected by pipes.
+     _________________________________________________________________
+
+    4.2.1.2. NOTATION
+
+   In command descriptions, "command" is replaced by a shell or system
+   command or pipeline. The command names specified in these commands are
+   interpreted by your shell, just as if you were typing them at the
+   shell prompt, and so if they are in your PATH, they will be found in
+   the expected manner. Therefore you don't have to specify complete
+   pathnames for commands that are programs (but it shouldn't hurt if you
+   do).
+
+   The normal notation for I/O redirection is as follows:
+
+  <  Read Stdin from the given file.
+  >  Send Stdout to the given file.
+  |  Send Stdout from the command on the left to the command on the right.
+
+   Examples:
+
+   sort < foo > bar
+          Sorts the lines in file "foo" and writes the results to file
+          "bar"
+
+   grep -c "some text" *.txt | grep -v ":0" | sort | pr -3 | lpr
+          This is a command pipeline composed of 5 commands:
+
+   grep -c "some text" *.txt
+          Looks in all files whose names end with ".txt" for the string
+          "some text" and writes to Stdout the names of each file
+          followed by a colon and the number of occurrences in each.
+
+   grep -v ":0"
+          Prints to Stdout the lines from Stdin that do NOT contain the
+          string ":0", in this case, it removes the names of files that
+          do not contain "some text".
+
+   sort
+          Sorts the lines from Stdin alphabetically to Stdout.
+
+   pr -3
+          Arranges the lines from Stdin in three columns.
+
+   lpr
+          Prints its Stdin on the default printer.
+
+   Note that the Kermit features described here work only with commands
+   that use Stdio. If you attempt to use them with commands whose input
+   and output can not be redirected, Kermit will most likely get stuck.
+   Kermit has no way of telling how an external command works, nor what
+   the syntax of the shell is, so it's up to you to make sure you use
+   these features only with redirectable commands.
+
+   The quoting rules of your shell apply to the command. Thus in UNIX,
+   where C-Kermit tries to use your preferred shell for running commands,
+   shell "metacharacters" within commands must be escaped if they are to
+   be taken literally, using the methods normal for your shell. For
+   example, the UNIX tr (translate) command must have its arguments in
+   quotes:
+
+  tr "[a-z]" "[A-Z]"
+
+   otherwise the shell is likely to replace them by all filenames that
+   match, which is probably not what you want. This is also true when
+   using your shell directly, and has nothing to do with Kermit.
+     _________________________________________________________________
+
+    4.2.1.3. SECURITY
+
+   Some sites might not wish to allow access to system commands or
+   external programs from within Kermit. Such access, including all the
+   features described here, can be disabled in various ways:
+
+    1. When building from source code, include -DNOPUSH among the CFLAGS.
+    2. At runtime, give the NOPUSH command.
+    3. For server mode, give the DISABLE HOST command.
+    4. Implicit use of pipes can be disabled as described in [440]Section
+       4.2.4.
+
+   Note: 3 and 4 are not necessary if you have done 1 or 2.
+     _________________________________________________________________
+
+    4.2.2. Commands for Transferring from and to Pipes
+
+   SEND /COMMAND sends data from a command or command pipeline, and
+   RECEIVE /COMMENT writes data to a command or pipeline. The GET
+   /COMMAND command asks a server to send material, and then writes the
+   incoming material to a command or pipeline. These features, along with
+   switches (like "/COMMAND", described in [441]Section 4.7) are new to
+   C-Kermit 6.1. The following synonyms are also provided:
+
+  CSEND    = SEND /COMMAND
+  CRECEIVE = RECEIVE /COMMAND
+  CGET     = GET /COMMAND
+
+   None of these commands can be used if a SEND or RECEIVE FILTER
+   (respectively, [442]Section 4.2.3) is in effect, or if a NOPUSH
+   command ([443]Section 4.2.1.3) has been given, or if the current
+   protocol is not Kermit.
+     _________________________________________________________________
+
+    4.2.2.1. Sending from a Command
+
+   SEND /COMMAND command [ as-name ]
+   SEND /AS-NAME:as-name /COMMAND command
+   CSEND command [ as-name ]
+          These three forms are the same. They work like the SEND
+          command, but instead of sending a file, it sends the standard
+          output of the given command, either under the command's own
+          name, or else with the given as-name. If the command contains
+          spaces, it must be enclosed in braces. Braces should also be
+          used for the as-name if it contains spaces. If braces are
+          included around either the command or the as-name, they are
+          removed after parsing but before use. As with SEND, the
+          transfer is in text or binary mode according the current FILE
+          TYPE setting, unless you override the global transfer mode by
+          including a /TEXT or /BINARY switch. The command must require
+          no input.
+
+   When sending from a command or pipeline, C-Kermit has no way of
+   knowing in advance how much data will be sent, and so it can not send
+   the size to the other Kermit in the Attribute packet, and so the
+   receiving Kermit has no way of displaying "percent done" or a progress
+   bar (thermometer).
+
+   Examples that make sense in text mode (illustrated by common UNIX
+   commands):
+
+   SEND /COMMAND finger
+   CSEND finger
+          sends the current "finger" listing (who's logged in) under the
+          name "finger". The two forms "send /command" and "csend" are
+          equivalent; we won't bother showing them both in the rest of
+          the examples.
+
+   SEND /COMMAND:{finger}
+   CSEND {finger}
+          Same as previous example (braces are removed from "{finger}").
+
+   SEND /COMMAND:{ finger }
+   CSEND { finger }
+          Same as previous example, but note that the spaces are kept.
+          This does not prevent the shell from running the "finger"
+          program, but its output is sent under the name " finger " (with
+          a leading and trailing space).
+
+   SEND /COMMAND:finger /AS-NAME:userlist
+   CSEND finger userlist
+          sends the current finger listing under the name "userlist".
+
+   SEND /COMMAND:{finger | sort -r} /AS-NAME:userlist
+   CSEND {finger | sort -r} userlist
+          sends the current finger listing, sorted in reverse order,
+          under the name "userlist". The braces are needed to distinguish
+          the command from the as-name.
+
+   SEND /COMMAND:{finger | sort -r} /AS-NAME:{userlist}
+   CSEND {finger | sort -r} {userlist}
+          Same as previous example (braces are removed from
+          "{userlist}").
+
+   SEND /COMMAND:{finger | sort -r}
+          /AS-NAME:{\freplace(\v(filename),\32,_)}
+
+   CSEND {finger | sort -r} {\freplace(\v(filename),\32,_)}
+          Like the previous example, but sends the output of the command
+          under the name of the command, but with all spaces (\32)
+          replaced by underscores, so the as-name is "finger_|_sort_-r".
+
+   Examples that make sense in binary mode (three equivalent forms are
+   shown):
+
+   SEND /COMMAND /BINARY {tar cf - . | gzip -c} mydir.tar.gz
+   SEND /COMMAND /BINARY /AS-NAME:mydir.tar.gz {tar cf - . | gzip -c}
+   CSEND /BINARY {tar cf - . | gzip -c} mydir.tar.gz
+          Makes a tar archive of the current directory, compresses it
+          with the GNU gzip program, and sends it as "mydir.tar.gz". The
+          other Kermit can, of course, just store it as a file, or it can
+          use CRECEIVE to uncompress and dearchive it as part of the
+          transfer process.
+
+   When using a "pipeline" of commands in the command field, obviously,
+   the first command must not require any input, and the last command
+   should produce some output, and all intermediate commands should get
+   some input and produce some output.
+     _________________________________________________________________
+
+    4.2.2.2. Receiving to a Command
+
+   RECEIVE /COMMAND command
+   CRECEIVE command
+          This is like RECEIVE, except incoming material is written to
+          the standard input of the given command, in text or binary mode
+          according to the normal rules for file reception. Be sure to
+          include a redirector to a file (if the command normally writes
+          to standard output), or the output of the command won't go
+          anywhere. The command may contain spaces; braces are not
+          needed, but they are removed if used.
+
+   WARNING: C-Kermit has no way of knowing anything about the command, or
+   even whether it is a command. Thus this command will always cause
+   C-Kermit to enter protocol mode, as long as some text is specified in
+   the command field. However, if the text does not correspond to a
+   command, the transfer will eventually fail with a message such as
+   "Error writing data" or "Failure to close file".
+
+   Examples for text mode (in UNIX):
+
+   RECEIVE /COMMAND sort -r > reverse.txt
+   CRECEIVE sort -r > reverse.txt
+          The text that is received is sorted in reverse order and stored
+          in the file "reverse.txt". The two forms shown are equivalent.
+
+   RECEIVE /COMMAND {sort -r > reverse.txt}
+   CRECEIVE {sort -r > reverse.txt}
+          The same as the previous example; if braces are included, they
+          are simply removed.
+
+   RECEIVE /COMMAND {sort -r > \flower(\v(filename)).reverse}
+   CRECEIVE {sort -r > \flower(\v(filename)).reverse}
+          Same but stores result under the incoming filename, lowercased,
+          and with ".reverse" appended to it.
+
+   RECEIVE /COMMAND sort
+   CRECEIVE sort
+          Does nothing useful, since the output of sort has nowhere to
+          go.
+
+   RECEIVE /COMMAND sort -r | pr -3 | lpr -Plaserjet
+   CRECEIVE sort -r | pr -3 | lpr -Plaserjet
+          The text that is received is sorted in reverse order, arranged
+          into three columns, and sent to the "laserjet" printer.
+
+   Examples for binary mode:
+
+   RECEIVE /COMMAND:{gunzip -c | tar xf -}
+   CRECEIVE {gunzip -c | tar xf -}
+          Assuming the data that is received is a compressed tar archive,
+          uncompresses the archive and passes it to tar for extraction.
+          In this case the braces are needed because otherwise the final
+          "-" would be taken as a command continuation character (see
+          [444]Using C-Kermit, 2nd Edition, p.33).
+
+   GET /COMMAND remote-file command
+   GET /COMMAND /AS-NAME:command remote-file
+   CGET remote-file command
+          This command tells the Kermit client to send a GET request for
+          the given remote file to a Kermit server. Unlike GET, however,
+          the incoming material is written to a command, rather than to a
+          file. If the remote-file or the command contain spaces, they
+          must be enclosed in braces. The same cautions about the command
+          apply as for CRECEIVE.
+
+   Examples (for UNIX):
+
+   GET /COMMAND oofa.txt sort -r > oofa.new
+   GET /COMMAND {oofa.txt} {sort -r > oofa.new}
+   CGET oofa.txt sort -r > oofa.new
+   CGET {oofa.txt} {sort -r > oofa.new}
+          These four are equivalent. Each of them requests the server to
+          send its "oofa.txt" file, and as it arrives, it is sorted in
+          reverse order and written to "oofa.new".
+
+   GET /COMMAND {profile exec a} lpr
+   GET /COMMAND {profile exec a} {lpr}
+   GET /COMMAND /AS-NAME:lpr {profile exec a}
+   GET /COMMAND /AS-NAME:{lpr} {profile exec a}
+   GET /COMMAND /AS:lpr {profile exec a}
+   CGET {profile exec a} lpr
+   CGET {profile exec a} {lpr}
+          Here the remote filename contains spaces so it MUST be enclosed
+          in braces. As it arrives it is sent to the lpr program for
+          printing. Braces are optional around "lpr" since it contains no
+          spaces.
+
+   GET /COMMAND *.txt {cat >> new.txt}
+   GET /AS-NAME:{cat >> new.txt} /COMMAND *.txt
+   CGET *.txt {cat >> new.txt}
+          This gets all the ".txt" files from the server and concatenates
+          them all into a single "new.txt" file on the client.
+
+   GET /COMMAND *.txt {echo \v(filename)>>new.txt;cat>>new.txt}
+   CGET *.txt {echo \v(filename)>>new.txt;cat>>new.txt}
+          As above, but inserts each file's name before its contents.
+     _________________________________________________________________
+
+    4.2.3. Using File-Transfer Filters
+
+   The commands described in [445]Section 4.2.2 let you send the output
+   of a command, or receive data into a command. But what if you want to
+   specify preprocessing for files that you send, or postprocessing of
+   files that you receive, even when multiple files are involved? For
+   this you need a way to specify send and receive filters. The commands
+   are SET SEND FILTER and SET RECEIVE FILTER; SHOW PROTOCOL displays the
+   current settings.
+
+    4.2.3.1. The SEND Filter
+
+   SET SEND FILTER [ command ]
+          This command specifies a command to be run on any file that you
+          SEND (or MOVE, MSEND, etc). It also applies to files sent when
+          in server mode, in response to GET commands, but not to the
+          results of REMOTE commands like REMOTE DIRECTORY, REMOTE TYPE,
+          REMOTE HOST, etc. The command may be, but need not be, enclosed
+          in braces; if it is, the braces are stripped before use. The
+          output of this command is sent, rather than the file itself.
+          The current FILE TYPE setting (TEXT or BINARY) applies to the
+          output of the command. The command must contain at least one
+          instance of \v(filename), for which the name of the actual file
+          is substituted. If the command is omitted, the send filter is
+          removed and files are sent in the normal manner.
+
+   The SET SEND FILTER sets up a "global" filter -- that is, one that
+   applies to all subsequent file-sending commands until you change or
+   remove it. You can also specify a "local" filter to be used in a
+   specific file-sending command by using the /FILTER switch (see
+   [446]Section 1.5); for example:
+
+  SEND /FILTER:command [ other-switches ] filename
+
+   Besides \v(filename), you can include any other script programming
+   notation in the send filter: variable names, array references, calls
+   to built-in string or other functions, and so on. These are evaluated
+   during file transfer, NOT during parsing, and they are evaluated
+   separately for each file.
+
+   When the SEND or MOVE (SEND /DELETE) command is used with a send
+   filter, the output from the filter is sent under the file's original
+   name unless you specify an "as-name" or template. The Attribute packet
+   (if any) contains the original file's attributes (size, creation date,
+   etc). So (for example) if the filter changes the file's size, the
+   progress thermometer might be wrong. (We can't send the size of the
+   output from the filter, because it is not known until the transfer is
+   finished.) If you prefer that the size not be sent, use "set
+   attributes size off".
+
+   You can not use send filters with RESEND (SEND /RECOVER) or PSEND
+   (SEND /START).
+
+   Examples for text mode:
+
+   SET SEND FILTER sort -r \v(filename) ; Braces may be omitted
+   SET SEND FILTER {sort -r \v(filename)} ; Braces may be included
+   SEND *.txt
+          This sends every file in the current directory whose name ends
+          with ".txt" under its own name, but with its lines sorted in
+          reverse order.
+
+   SEND /FILTER:{sort -r \v(filename)} *.txt
+          Same as above, but the filter applies only to this SEND
+          command. Braces are required in this case.
+
+   SET SEND FILTER {sort -r \v(filename)}
+   SEND oofa.txt reverse.txt
+          Sends the oofa.txt file with its lines sorted in reverse order
+          under the name "reverse.txt".
+
+   SET SEND FILTER {sort -r \v(filename)}
+   SEND oofa.* \v(filename).reverse
+          Sends all the oofa.* files with their lines sorted in reverse
+          order; each file is sent under its own name but with ".reverse"
+          appended to it.
+
+   SET SEND FILTER {tr "[a-z]" "[A-Z]" < \v(filename)}
+   SEND *.txt
+          Sends all ".txt" files under their own names, but uppercasing
+          their contents.
+
+   Note that the SEND FILTER applies not only to files that are sent with
+   SEND, MOVE, MSEND, etc, but also to files sent by the C-Kermit server
+   in response to GET requests.
+
+   Examples for binary mode:
+
+   SET SEND FILTER {gzip -c \v(filename)}
+   SEND /BINARY oofa.txt oofa.txt.gz
+          Sends the oofa.txt file, compressed by gzip, as oofa.txt.gz.
+
+   SEND /BINARY /FILTER:{gzip -c \v(filename)} oofa.txt oofa.txt.gz
+          As above, but the filter applies only to this SEND command.
+
+   SET SEND FILTER {gzip -c \v(filename)}
+   SEND /BINARY oofa.* \fupper(\replace(\v(filename),.,_)).GZ
+          Sends all the oofa.* files, compressed by gzip, each under its
+          own name, but with the name uppercased, all periods within the
+          name converted to underscores, and ".GZ" appended to it. So,
+          for example, "oofa.txt" is sent as "OOFA_TXT.GZ".
+
+   In the gzip examples, note that the amount of data that is sent is
+   normally less than the original file size because gzip compresses the
+   file. But Kermit sends the original file size ahead in the attribute
+   packet anyway (unless you tell it not too). Thus the transfer will
+   probably appear to terminate early, e.g. when the receiver's
+   file-transfer display thermometer is only at 40%. If this annoys you,
+   tell Kermit to "set attribute length off". On the other hand, you can
+   use the final position of the thermometer as a measure of the
+   effectiveness of compression.
+     _________________________________________________________________
+
+    4.2.3.2. The RECEIVE Filter
+
+   SET RECEIVE FILTER [ command ]
+          This command specifies that the given command will be run on
+          any file that is received before it is written to disk. The
+          command may be, but need not be, enclosed in braces; if it is
+          the braces are stripped before use. The following two commands
+          are equivalent:
+
+  SET RECEIVE FILTER sort -r > \v(filename)
+  SET RECEIVE FILTER {sort -r > \v(filename)}
+
+   The RECEIVE filter command may contain a "\v(filename)" sequence to be
+   replaced by the incoming filename from the file header packet, but it
+   is not required. However you must use it whenever your filter would
+   normally write to Stdout, otherwise its output will be lost.
+
+   The RECEIVE filter command may contain one or more "\v(filename)"
+   sequence to be replaced by the incoming filename from the file header
+   packet, but it is not required. However you must use it whenever your
+   filter would normally write to Stdout, otherwise its output will be
+   lost.
+
+   RECEIVE /FILTER:command and GET /FILTER:command can also be used to
+   specify a filter to be used for only one file-transfer operation.
+
+   UNIX examples for text mode:
+
+   SET RECEIVE FILTER lpr
+   RECEIVE
+          All the files that are received are sent to the default UNIX
+          print spooler.
+
+   RECEIVE /FILTER:lpr
+          Same as above, except the lpr filter is used only with this
+          RECEIVE command.
+
+   RECEIVE lpr
+          This is probably not what you want; it creates a file called
+          lpr.
+
+   SET RECEIVE FILTER {sort -r > \v(filename)}
+   RECEIVE
+          Stores each incoming file with its lines sorted in reverse
+          order, under its own name.
+
+   RECEIVE /FILTER:{sort -r > \v(filename)}
+          As above, but the filter is used only for this RECEIVE command.
+
+   SET RECEIVE FILTER sort -r > \v(filename)
+   RECEIVE reverse.txt
+          Stores each incoming file with its lines sorted in reverse
+          order, under the name "reverse.txt". The actual result depends
+          on the FILE COLLISION setting. If it is OVERWRITE and multiple
+          files arrive, then each incoming file destroys the previous
+          one. If it is BACKUP (the default), filename conflicts are
+          resolve by adding "version numbers" to the filenames:
+          reverse.txt, reverse.txt.~1~, reverse.txt.~2~, etc.
+
+   SET RECEIVE FILTER sort -r > \v(filename)
+   RECEIVE \v(filename).reverse
+          Stores each incoming file with its lines sorted in reverse
+          order, under the name it arrived with, but with ".reverse"
+          appended to it.
+
+   SET RECEIVE FILTER sort -r > \v(filename)
+   RECEIVE \flower(\v(filename)).reverse
+          Like the previous example, but ensures that the filename is
+          lowercase.
+
+          Examples for binary mode:
+
+   SET RECEIVE FILTER gunzip -c > \v(filename)
+   RECEIVE
+          This receives one or more presumably compressed file and
+          uncompresses each one into a file having the same name it was
+          sent with. For example, if the file is sent with the name
+          OOFA.TXT.GZ, it is stored with that name, even after
+          decompression.
+
+   SET RECEIVE FILTER gunzip -c > \v(filename)
+   RECEIVE \flower(\fsubstring(\v(filename),1,\flength(\v(filename))-3))
+          Like the previous example, but the resulting filename has its
+          rightmost three characters removed from it and the remainder is
+          lowercased. So if the incoming filename is OOFA.TXT.GZ, it is
+          stored as oofa.txt after decompression.
+
+   Of course you don't want to type such long hideous commands, so we
+   have also introduced several new functions:
+
+   \fstripx(string[,character])
+          This function removes the rightmost segment of the string that
+          starts with the given character. If no character is given,
+          period (.) is used. Thus it is most conveniently used for
+          stripping the extension from a filename (or the decimal portion
+          from a floating-point number written in US/UK style). Examples:
+
+   \fstripx(OOFA.TXT.GZ)             => OOFA.TXT
+   \fstripx(OOFA.TXT.GZ,.)           => OOFA.TXT
+   \fstripx(OOFA.TXT.GZ,X)           => OOFA.T
+   \fstripx(\fstripx(OOFA.TXT.GZ))   => OOFA
+   \fstripx($100.00)                 => $100
+
+   \fstripn(string,number)
+          Removes the rightmost number characters from the string.
+          Examples:
+
+   \fstripn(OOFA.TXT.GZ)             => OOFA.TXT.GZ
+   \fstripn(OOFA.TXT.GZ,3)           => OOFA.TXT
+   \fstripn(OOFA.TXT.GZ,7)           => OOFA
+
+   \fstripb(string[,c1[,c2]])
+          Strips enclosing matching braces, brackets, parentheses, or
+          quotes from the string. The second argument, c1, specifies
+          which kind of enclosure to look for; if not specified, any
+          enclosing (), [], <>, {}, "", '', or `' are removed. If c1 is
+          specified and c2 is not, then if c1 is an opening brace,
+          bracket, or parenthesis, the matching closing one is supplied
+          automatically as c2. If both c1 and c2 are specified, then to
+          be stripped the string must begin with c1 and end with c2. If
+          the string is not enclosed in the indicated manner, the result
+          is the original string. Examples:
+
+   \fstripb("abc")                   => abc
+   \fstripb([abc])                   => abc
+   \fstripb([abc)                    => [abc
+   \fstripb(<abc>)                   => abc
+   \fstripb(<abc>,[)                 => <abc>
+   \fstripb((abc))                   => abc
+   \fstripb((abc),[)                 => (abc)
+   \fstripb((abc),{(})               => abc
+   \fstripb(+abc+)                   => +abc+
+   \fstripb(+abc+,+)                 => abc
+   \fstripb(+abc+,+,^)               => +abc+
+   \fstripb(+abc^,+,^)               => abc
+   \fstripb('abc')                   => abc
+   \fstripb(`abc')                   => abc
+   \fstripb(``abc'')                 => `abc'
+   \fstripb(\fstripb(``abc''))       => abc
+
+          Notice the special syntax required for including a literal
+          parenthesis in the argument list. As the last two examples
+          illustrate, \fstripb() strips only one level at at a time;
+          nesting can be used to strip a small fixed number of levels;
+          loops can be used to strip larger or indeterminate numbers of
+          levels.
+
+   \flop(string[,char])
+          Removes the leftmost segment of the string that ends with the
+          given character. If no character is given, period (.) is used.
+          Examples:
+
+  \flop(OOFA.TXT.GZ)               => TXT.GZ
+  \flop(OOFA.TXT.GZ,.)             => TXT.GZ
+  \flop(OOFA.TXT.GZ,X)             => T.GZ
+
+          To remove the leftmost number characters, just use
+          \fsubstring(s,number+1). To return the rightmost number
+          characters, use \fright(s,number).
+
+   So the hideous example:
+
+  receive \flower(\fsubstring(\v(filename),1,\flength(\v(filename))-3))
+
+   can now be written as:
+
+  receive \flower(\fstripx(\v(filename)))
+
+   That is, the filename stripped of its extension and then lowercased.
+   This is not only shorter and less hideous, but also does not depend on
+   the length of the extension being 3.
+
+   Note that when a receive filter is in effect, this overrides your FILE
+   COLLISION setting, since Kermit has no way of knowing what the final
+   destination filename will be (because it does not know, and can not be
+   expected to know, the syntax of every version of every command shell
+   on every platform on the planet).
+     _________________________________________________________________
+
+    4.2.4. Implicit Use of Pipes
+
+   If you wish, C-Kermit can also examine incoming filenames to see if
+   they start with "!", and if so, the subsequent text is treated as a
+   command to read from or write to. For example, if a Kermit client is
+   given the following command:
+
+  get {!finger | sort}
+
+   the server on the other end, if it supports this feature, will run the
+   "finger" program, pipe its standard output to the "sort" program, and
+   send sort's standard output back to you. Similarly, if you:
+
+  send oofa.txt !sort -r > oofa.new
+
+   or, equivalently:
+
+  send oofa.txt {!sort -r > oofa.new}
+
+   or:
+
+  send /as-name:{!sort -r > oofa.new} oofa.txt
+
+   this has the receiver send the contents of the incoming oofa.txt file
+   to the sort program, which sorts the text in reverse order and stores
+   the result in oofa.new.
+
+   This use of the exclamation mark should be familiar to UNIX users as
+   the "bang" feature that lets you run an external application or
+   command from within another application.
+
+   Kermit's "bang" feature is disabled by default, since it is not
+   unheard for filenames to actually begin with "!". So if you want to
+   use this feature, you must enable it with the following command:
+
+   SET TRANSFER PIPES { ON, OFF }
+          ON enables the recognition of "!" notation in incoming
+          filenames during file transfer as an indicator that the
+          remaining text is the name of a command. OFF, the default,
+          disables this feature and uses the text as a filename in the
+          normal fashion. This command does NOT affect SEND /COMMAND, GET
+          /COMMAND, CSEND, etc.
+
+   So using a combination of CSEND (SEND /COMMAND) and the "bang"
+   feature, you can transfer a directory tree all in one command
+   (assuming the remote Kermit supports pipe transfers and has them
+   enabled):
+
+  CSEND {tar cf - . | gzip -c} {!gunzip -c | tar xf -}
+
+   or:
+
+  SEND /COMMAND:{tar cf - . | gzip -c} /as:{!gunzip -c | tar xf -}
+
+   Pay close attention to the syntax. Braces are needed around the
+   command because it contains spaces; braces are needed around the
+   as-name because it ends with "-". The as-name must begin with "!" or
+   receiving Kermit will not recognize it as a command. The CSEND command
+   must NOT begin with "!" unless you are running a command whose name
+   really does start that character.
+
+   Similarly, you have a Kermit server send a directory tree to be
+   unpacked on the client end:
+
+  CGET {!tar cf - . | gzip -c} {gunzip -c | tar xf -}
+
+   or:
+
+  GET /COMMAND {!tar cf - . | gzip -c} /as:{gunzip -c | tar xf -}
+
+   Notice how, in this case, the bang is required in the remote command,
+   to distinguish it from a filename, but not in the local command, since
+   by definition of CGET (or GET /COMMAND), it is known to be a command.
+
+   SEND and RECEIVE FILTERs supersede the bang feature. For example, if a
+   file arrives under the name "!gunzip -c | tar xf -", but the receiving
+   Kermit also has been given a command like:
+
+  set receive filter sort -r > \v(filename)
+
+   then the incoming data will be sorted rather than gunzipped.
+
+   Finally, if SET TRANSFER PIPES is ON (and in this case, this must be
+   done in your C-Kermit initialization file), you can send from a pipe
+   on the C-Kermit command line:
+
+  kermit -s "!finger | sort -r" -a userlist
+
+   In this case the "filename" contains spaces and so must be quoting
+   using your shell's quoting rules.
+     _________________________________________________________________
+
+    4.2.5. Success and Failure of Piped Commands
+
+   Commands or programs started by Kermit as a result of CSEND or
+   CRECEIVE commands, CGET, SEND /COMMAND, REDIRECT commands (see
+   [447]Section 4.2.8.2), implicit use of pipes, RUN commands, and so
+   forth, should return their exit status codes to the Kermit command
+   that caused them to be run, and therefore IF SUCCESS and IF FAILURE
+   tests after these commands should work as expected. For example:
+
+  CSEND blah < filename
+
+   should fail if there is no command called "blah" or if there is no
+   file called "filename". However, this is not foolproof and sometimes
+   C-Kermit might think a command succeeded when it failed, or vice
+   versa. This is most likely to happen when the highly system-dependent
+   methods that Kermit must use to determine a command's exit status code
+   do not supply the right information.
+
+   It can also happen because some commands might define success and
+   failure differently from what you expect, or because you are using a
+   pipeline composed of many commands, and one of them fails to pass
+   failing exit status codes up the chain. The most likely culprit is the
+   shell itself, which in most cases must be interposed between Kermit
+   and any external program to be run.
+
+   In any case, you can examine the following variable to find out the
+   exit status code returned to Kermit by the process most recently run
+   by any command that runs external commands or programs, including
+   CSEND, CRECEIVE, REDIRECT, RUN, etc:
+
+  \v(pexitstat)
+
+   In UNIX, Windows and OS/2, the value should be -2 if no command has
+   been run yet, 0 if the most recent command succeeded, -1, -3, or -4 if
+   there was an internal error, and a positive number returned by the
+   command itself if the command failed. If the number is in the range
+   1-127, this is the program's exit status code. If it is 128 or
+   greater, this is supposed to indicate that the command or program was
+   interrupted or terminated from outside itself.
+
+   In Windows 95 and 98, the return values of the default shell are
+   unreliable; various third-party shells can be used to work around this
+   deficiency.
+
+   In VMS, it is the actual exit status code of the command that was run.
+   This is an odd number if the command succeeded, and an even number if
+   it failed. You can see the associated message as follows:
+
+  run write sys$output f$message(\v(pexitstat))
+
+   Or, more conveniently, use the new Kermit function:
+
+  echo \ferrstring(\v(pexitstat))
+
+   which converts a system error code (number) to the corresponding
+   message.
+     _________________________________________________________________
+
+    4.2.6. Cautions about Using Pipes to Transfer Directory Trees
+
+   Although utilities such as tar and zip/unzip might be available on
+   different platforms (such as UNIX and Windows), this does not
+   necessarily mean you can use them successfully to transfer directory
+   trees between unlike platforms. For example:
+
+  CSEND {tar cf - . | gzip -c} {!gunzip -c | tar xf -}
+
+   when used from UNIX to Windows will have satisfactory results for
+   binary files, but not for text files. UNIX text files have lines
+   ending with Linefeed (LF) only, whereas Windows text files have lines
+   ending in Carriage Return and Linefeed (CRLF). Thus any text files
+   that were in the archive formed by the first tar command will be
+   unpacked by the second tar command in their original form, and will
+   display and print incorrectly in Windows (except in applications that
+   have been explicitly coded to handle UNIX-format text files). On the
+   other hand if you told gzip to use "text mode" to do record format
+   conversion (assuming there was a way to tell it, as there is with most
+   "zip" programs), this would destroy any binary files in the archive.
+
+   Furthermore, if the archive contains text files that are written in
+   languages other than English, the "special" (accented and/or
+   non-Roman) characters are NOT translated, and are therefore likely
+   show up as gibberish on the target system. For example, West European
+   languages are usually encoded in ISO Latin Alphabet 1 in UNIX, but in
+   PC code page 850 on the PC. Capital A with acute accent is code point
+   193 (decimal) Latin-1, but 181 in CP850. So A-acute in the UNIX file
+   becomes Middle Box Bottom on the PC, and similarly for all the other
+   special characters, and for all other languages -- Greek, Russian,
+   Hebrew, Japanese, etc.
+
+   So when transferring text files between unlike platforms, you should
+   use direct Kermit file transfers so Kermit can apply the needed
+   record-format and character-set transformations. Use pipelines
+   containing archivers like tar or zip only if all the files are binary
+   or the two systems use the same record format and character set for
+   text files.
+
+   Also see [448]Sections 4.3, [449]4.10, [450]4.11, and [451]4.15 for
+   how to transfer directory trees between both like and unlike systems
+   directly with Kermit.
+     _________________________________________________________________
+
+    4.2.7. Pipes and Encryption
+
+   Of course pipelines could be used for encrypted file transfers,
+   assuming proper precautions could be taken concerning the transmission
+   of the key. But there is rarely a good way to do this. To illustrate
+   using UNIX crypt:
+
+  csend {crypt key < filename} {!crypt key > filename}
+
+   Or, more ambitiously:
+
+  csend {tar cf - . | gzip -c | crypt key} {!crypt key | gunzip -c | tar xf -}
+
+   transmits the key in the file header packet as part of the
+   (clear-text) remote command, defeating the entire purpose of
+   encrypting the file data.
+
+   But if you are connected in terminal mode to the remote computer and
+   type:
+
+  creceive {crypt key > filename}
+
+   at the remote Kermit prompt, you have also transmitted the key in
+   clear text over the communications link.
+
+   At present, the only secure way to use CSEND and CRECEIVE with an
+   encryption filter is to have a human operator at both ends, so the key
+   does not have to be transmitted.
+
+   Theoretically it would be possible to use PGP software (Pretty Good
+   Privacy, by Phil Zimmerman, Phil's Pretty Good Software) to avoid key
+   transmission (since PGP uses separate public and private key and "lets
+   you communicate securely with people you've never met, with no secure
+   channels needed for prior exchange of keys"), but the specific method
+   has yet to be worked out.
+
+     HINT: See the PGP User's Guide, e.g. at:
+     [452]http://www.telstra.com.au/docs/PGP/
+     Especially the topic "Using PGP as a UNIX-Style Filter":
+     [453]http://www.telstra.com.au/docs/PGP/pgpdoc2/pgpdoc2_17.html
+
+   In any case, better and more convenient security options are now
+   available: Kerberos authentication and encryption ([454]CLICK HERE for
+   details) and the new ability to run C-Kermit "though" other
+   communication programs, described in [455]Section 2.7.
+     _________________________________________________________________
+
+    4.2.8. Commands and Functions Related to Pipes
+
+    4.2.8.1. The OPEN !READ and OPEN !WRITE Commands
+
+   These are described in [456]Using C-Kermit, and are generally useful
+   with reading output from commands that produce more than one line on
+   their standard output, or writing multiple lines into commands that
+   accept them on their standard input.
+
+   In C-Kermit 7.0 CLOSE !READ is accepted as a synonym for CLOSE READ,
+   and CLOSE !WRITE for CLOSE WRITE.
+
+   Testing the success and failure of these commands, however, can be a
+   bit tricky. Consider:
+
+  open !read lalaskjfsldkfjsldkfj
+
+   (where "lalaskjfsldkfjsldkfj" is neither a valid command nor the name
+   of a program or script that can be run). OPEN !READ, in UNIX at least,
+   translates this into execl(shellpath,shellname,"-c",command). This
+   means it starts your preferred shell (e.g. from the SHELL environment
+   variable) and asks it to execute the given command. It must be this
+   way, because your command can be a either an internal shell command
+   (which only your shell can execute) or an external command, which only
+   your shell knows how to find (it knows your PATH and interprets, etc).
+   Therefore unless OPEN !READ can't start your shell, it always
+   succeeds.
+
+   Continuing with the nonexistent-command example:
+
+  C-Kermit> open !read lalaskjfsldkfjsldkfj
+  C-Kermit> status
+   SUCCESS
+  C-Kermit> read line
+  C-Kermit> status
+   SUCCESS
+  C-Kermit> echo "\m(line)"
+  "bash: lalaskjfsldkfjsldkfj: command not found"
+  C-Kermit> close read
+  C-Kermit> status
+   FAILURE
+  C-Kermit>
+
+   In other words, the failure can not be detected on OPEN, since the
+   OPEN command succeeds if it can start your shell. It can't be detected
+   on READ, since all this does is read output from the shell, which in
+   this case happens to be an error message. However, failure IS detected
+   upon close, since this is the occasion upon which the shell gives
+   Kermit its exit status code.
+
+   For an illustration of this situation, see [457]Section 2.14.
+     _________________________________________________________________
+
+    4.2.8.2. The REDIRECT Command
+
+   A second method of I/O redirection is offered by the REDIRECT command.
+   This is a rather advanced and tricky feature that is presently
+   supported only in UNIX C-Kermit, in OS-9 C-Kermit, and in Kermit 95.
+   Syntax:
+
+   REDIRECT command
+          Runs the given command, sending its standard output to the
+          current communications channel (SET LINE, SET PORT, or SET HOST
+          connection), and reading its standard input from the same
+          connection. Works only in local mode -- i.e. a connection is
+          required -- and then only if the given command uses Standard
+          I/O.
+
+   Example:
+
+  redirect finger
+
+   runs the local "finger" command and sends its output over the
+   connection as plain text, where presumably there is a process set up
+   to read it. Another example:
+
+  redirect finger | sort -r
+
+   shows the use of a pipeline.
+
+   Note: REDIRECT differs from CSEND/CRECEIVE in two important ways: (1)
+   it does not use the Kermit protocol, and (2) it uses a bidirectional
+   pipe rather than a one-way pipe.
+
+   The primary use of the REDIRECT command is to run external protocols,
+   such as sz/rz in UNIX for ZMODEM, when they work over Standard I/O(*).
+   Example:
+
+  set host xyzcorp.com
+  (login, etc)
+  redirect sz oofa.zip
+
+   lets you make a Telnet connection with C-Kermit and then do a ZMODEM
+   transfer over it. ZMODEM protocol messages go both ways over the same
+   connection simultaneously.
+
+   It is possible to use C-Kermit on UNIX as your PPP dialer and then to
+   REDIRECT the connection to the PPP software, but C-Kermit 7.0 offers a
+   better approach to PPP dialing in its new EXEC command ([458]Section
+   1.23).
+
+   In theory, you can also redirect an interactive process. For example,
+   suppose you tell Kermit 95 to wait for an incoming TCP/IP connection:
+
+  set host * 3000
+
+   and then tell C-Kermit on UNIX to:
+
+  set host kermit95hostname 3000
+  redirect ksh
+
+   and then tell Kermit 95 to CONNECT: now you are talking to the UNIX
+   K-shell; you can give commands (pwd, ls, etc) and see the results. In
+   practice, the K-shell's terminal modes are messed up because (a) it is
+   not going through the Unix terminal driver, and (b) it is "smart" and
+   knows it is being redirected, and so acts in a decidedly inhospitable
+   manner (other applications like EMACS, vi, etc, simply refuse to run
+   if their standard i/o has been redirected).
+
+     (*) The publicly-distributed sz/rz programs do not work as clients.
+     However, Omen Technology does offer an up-to-date redirectable
+     client XYZMODEM program called crzsz.
+     _________________________________________________________________
+
+    4.2.8.3. Receiving Mail and Print Jobs
+
+   As of 7.0, and in UNIX only, files that are sent to C-Kermit as mail
+   (when the other Kermit uses a MAIL or SEND /MAIL command) or to be
+   printed (via REMOTE PRINT or SEND /PRINT) are now piped directly to
+   the mail or print program, rather than written to temporary files and
+   then mailed or printed and then deleted. This has the advantages of
+   (a) not requiring a temporary file, and (b) allowing mail to have a
+   proper subject in place of the filename. Temporary files were bad not
+   only because they required (a) space, and (b) writeability of the
+   current directory, but also because using them could result in wiping
+   out an existing file. See [459]Section 4.7 for more about SEND /MAIL
+   and SEND /PRINT.
+     _________________________________________________________________
+
+    4.2.8.4. Pipe-Related Functions
+
+   The \fcommand(command) function runs the given shell or system command
+   and returns the command's standard output as its value (with any
+   newline characters stripped from the end), unless the result is too
+   long, in which case it returns the empty string. The maximum length
+   for the result is at least 1022 bytes, and it might be longer on some
+   platforms. Examples (UNIX):
+
+  C-Kermit> echo "\fcommand(date)"
+  "Fri Apr 18 13:31:42 1997"
+  C-Kermit> echo "\fcommand(finger | wc -l)" ; how many users logged in?
+  "      83"
+  C-Kermit> evaluate \fcommand(finger | wc -l) * 2
+  166
+  C-Kermit> echo Welcome to \fcommand(tty) on \fcommand(date)
+  Welcome to /dev/ttyre on Fri Apr 18 13:31:42 1997
+  C-Kermit> echo "\fcommand(ls oofa.*)"
+  "oofa.c
+  oofa.h
+  oofa.o"
+  C-Kermit> cd /directory-with-thousands-of-files
+  C-Kermit> echo "\fcommand(ls -l)" ; This would be too long
+  ""
+  C-Kermit>
+
+   If a command's output would be too long, you can use the other, more
+   laborious method of reading from a command: OPEN !READ command, READ
+   each line, CLOSE !READ.
+
+   The \frawcommand(command) function is identical to \fcommand(command),
+   except it does not remove trailing newline characters:
+
+  C-Kermit> echo "\frawcommand(date)"
+  "Fri Apr 18 13:31:42 1997
+  "
+  C-Kermit> echo "\frawcommand(ls oofa.*)"
+  "oofa.c
+  oofa.h
+  oofa.o
+  "
+  C-Kermit>
+
+   Use \frawcommand() if you want to retain the final line terminators,
+   or if the command's output is "binary". But remember that if the
+   result of this (or any other) function contains any NUL (ASCII code 0)
+   characters, the first NUL will terminate the result string because
+   this is how C strings work (it's "C-Kermit", remember?).
+
+   These functions are useful not only locally, but also in the
+   client/server arena. If you need to get the results from a system
+   command on the server end into a variable on the client end, just do:
+
+  [ remote ] query kermit command(date)
+
+   The result is in the local \v(query) variable; see [460]Using
+   C-Kermit, 2nd Ed., pp.359-360 for details.
+     _________________________________________________________________
+
+  4.3. Automatic Per-File Text/Binary Mode Switching
+
+   When transferring files between like systems (e.g. UNIX-to-UNIX),
+   binary mode can be used for all files unless character-set translation
+   is needed, and in fact Kermit programs of recent vintage recognize
+   each others' platforms and switch to binary mode automatically when it
+   is appropriate (e.g. DOS to OS/2, or UNIX to UNIX). (Exception:
+   LABELED mode is chosen for VMS-to-VMS and OS/2-to-OS/2 transfers so
+   complex file formats can be preserved.)
+
+   On a client/server connection between like systems, the transfer mode
+   is currently determined by the file sender, rather than always by the
+   client. If the client is sending, it controls the transfer mode. If a
+   GET command is sent to the server, the server sends all files in
+   binary mode if its TRANSFER CHARACTER-SET is TRANSPARENT; otherwise it
+   uses text mode for text files (according to its text-pattern list) and
+   binary mode for binary files. Of course, the client can control the
+   server's transfer character-set with the REMOTE SET TRANSFER
+   CHARACTER-SET command.
+
+   When transferring files between unlike systems, however, (e.g.
+   UNIX-to-DOS), some files (such as executable program images) must be
+   transferred in binary mode but others (such as plain-text files) must
+   be transferred in text mode so their record format and character sets
+   can be appropriately converted. If a binary file is transferred in
+   text mode, it is ruined. If a text file is transferred in binary mode,
+   then at the very least, its format can be incorrect; at worst it is
+   also corrupted because its character set was not converted (in extreme
+   cases the corruption is total, e.g. because one system is ASCII-based
+   and the other EBCDIC).
+     _________________________________________________________________
+
+    4.3.1. Exceptions
+
+   VMS C-Kermit, when sending files to a non-VMS system, switches to text
+   or binary mode automatically for each file, based on the record format
+   in the file's directory entry; thus the mechanisms described in this
+   section do not apply to VMS C-Kermit, yet the effect is the same:
+   automatic text/binary mode switching when VMS C-Kermit is sending
+   files. See the VMS Appendix of [461]Using C-Kermit for details.
+
+   Kermit versions that support LABELED or IMAGE transfer mode are
+   likewise not affected by this feature when one of those modes is
+   selected (normally used only when transferring between like systems).
+
+   Kermit versions that support file-transfer pipes and filters are not
+   affected by this feature when pipes or filters are used, since the
+   output of a pipe or filter (such as gzip) is likely to require
+   transfer in a different mode than the original file.
+
+   Finally, SEND /TEXT or SEND /BINARY will force files to be sent in the
+   indicated mode, overriding all automatic transfer-mode-choosing
+   mechanisms.
+     _________________________________________________________________
+
+    4.3.2. Overview
+
+   Suppose you give C-Kermit a command like:
+
+  SEND *.*
+
+   And suppose the pattern *.* matches a mixture of text files (such as
+   program source code) and binary files (such os object modules or
+   executable programs).
+
+   C-Kermit 6.0 and earlier (except on VMS) send all files in the same
+   mode: whatever you said in your most recent SET FILE TYPE command, or
+   else whatever mode was chosen automatically according to the rules on
+   page 236 of Using C-Kermit, 2nd Ed.
+
+   But when text and binary files are mixed in the same group, and the
+   files are being transferred to an unlike system (e.g. UNIX to IBM
+   Mainframe), this results in corruption of either all the text files or
+   all the binary files.
+
+   Stream-oriented file systems such as in UNIX and DOS do not record any
+   information about the file to tell us whether the file should be
+   transferred in binary or text mode, making it impossible to select the
+   transfer mode for each file in a group automatically with any
+   certainty.
+
+   However, we can use some fairly-well established file naming
+   conventions for this purpose. C-Kermit 7.0 lets you provide lists of
+   filename patterns that are used to separately determine the file type
+   for each individual file being transfered. A pattern is a string,
+   possibly containing the special characters "*" (asterisk, which
+   matches any string of zero of more characters) and/or "?" (question
+   mark, which matches any single character). For example "a*b" matches
+   all files whose names start with "a" and end with "b", such as "ab",
+   "arb", "ababababab", etc, but not "abba". And "a?b" matches any file
+   whose name starts with "a", ends with "b", and is exactly 3 characters
+   long.
+
+     NOTE: When typing commands at the C-Kermit prompt, you must prefix
+     "?" with \ to override its normal function of giving help.
+
+   (Also see [462]Section 4.9 for additional pattern-matching notations
+   that might be available in your version of C-Kermit.)
+
+   When you have specified filename recognition patterns, C-Kermit can
+   transfer the ones whose names match any of the binary-mode patterns in
+   binary mode, and those with names that match any of the text-mode
+   patterns in text mode, and those whose names match neither in the
+   prevailing mode you have chosen, or that was chosen automatically via
+   peer recognition.
+     _________________________________________________________________
+
+    4.3.3. Commands
+
+   SET FILE PATTERNS { ON, OFF, AUTO }
+          This tells Kermit whether to do per-file filename
+          pattern-matching to determine text or binary mode. The normal
+          and default setting is AUTO, which means to use pattern lists
+          to switch transfer mode only when it is certain that the other
+          Kermit program supports automatic notification of transfer mode
+          (via Attribute packets) on a per-file basis (this information
+          is obtained automatically during protocol startup negotiation).
+          ON means to always determine the transfer mode from the
+          filename and pattern list when sending files. Use OFF to
+          disable this feature (without resetting your pattern lists).
+          Also note that if you have selected LABELED file transfer (SET
+          FILE TYPE LABELED), this takes precedence over
+          filename-matching patterns and all files are sent in labeled
+          mode.
+
+   SET TRANSFER MODE MANUAL
+          Disables the use of filename patterns, no matter what the FILE
+          PATTERNS setting.
+
+   REMOTE SET TRANSFER MODE MANUAL
+          Client command to disable automatic transfer mode, and
+          therefore also filename patterns, in the server. Synonym:
+          REMOTE SET XFER MODE MANUAL.
+
+   { GET, SEND, etc } { /BINARY, /TEXT }
+          Including a /BINARY or /TEXT (or, where supported, /IMAGE or
+          /LABELED) switch with a file-transfer command changes the
+          transfer mode to manual for that command only, and therefore
+          disables patterns that that command.
+
+   SET FILE BINARY-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+          A list of zero or more patterns, separated by spaces (not
+          commas). Letters in a pattern are case-sensitive if the
+          underlying filenames are case sensitive (as in UNIX), and
+          case-insensitive otherwise (as in Windows). If a file's name is
+          matched by any pattern in the list and SET FILE PATTERNS is ON,
+          the file is sent in binary mode. Examples:
+
+  SET FILE BINARY-PATTERNS *.gz *.Z *.tar *.zip *.o *.so *.a *.out ; UNIX
+  SET FILE BINARY-PATTERNS *.EXE *.ZIP *.OBJ *.COM ; DOS or OS/2 or Windows
+
+          If a pattern contains spaces, enclose it in braces.
+
+   SET FILE TEXT-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+          Like SET FILE BINARY-PATTERNS, but the patterns choose text
+          files rather than binary ones. Examples:
+
+  SET FILE TEXT-PATTERNS *.TXT *.KSC *.HTM* *.BAT ; DOS, Windows, OS/2
+
+   ADD BINARY-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+          Adds one or more patterns to the BINARY-PATTERN list.
+
+   ADD TEXT-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+          Adds one or more patterns to the TEXT-PATTERN list.
+
+   REMOVE BINARY-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+          Removes one or more patterns from the BINARY-PATTERN list. The
+          given patterns are matched with the ones in the BINARY-PATTERNS
+          list with case sensitivity if the underlying file system has
+          case-sensitive names (as do UNIX and OS-9), otherwise with case
+          independence.
+
+   REMOVE TEXT-PATTERNS [ pattern [ pattern [ pattern ... ] ] ]
+          Removes one or more patterns from the TEXT-PATTERN list.
+
+   SHOW PATTERNS
+          Displays the current pattern selections.
+
+   Whenever you give a SET FILE BINARY-PATTERNS or SET FILE TEXT-PATTERNS
+   command, the previous list is replaced. If you give one of these
+   commands without a pattern list, the previous list is removed.
+
+   When patterns are active and files are being sent, text patterns (if
+   any) are applied first (but only if not RESENDing and not sending in
+   LABELED mode), then binary patterns, so if the same pattern appears in
+   both lists, binary mode is chosen.
+     _________________________________________________________________
+
+    4.3.4. Examples
+
+   Here's an example that might be used when sending files from UNIX:
+
+  set file type binary
+  set file text-patterns *.c *.h *.w *.txt makefile
+  set file binary-patterns *.o
+  msend makefile wermit wart ck*.[cwho] ck*.txt
+
+   Note that "wermit" and "wart" do not match any patterns so they are
+   sent in the prevailing mode, which is binary. Also note the use of
+   "makefile" as a pattern that does not contain any wildcard characters
+   (there is no other convention to distinguish among "wermit" and
+   "wart", which are binary executables, and "makefile", which is a text
+   file, purely by their names).
+
+   Most C-Kermit implementations have a default pattern list built in,
+   which includes patterns that are almost certain to succeed in picking
+   the right transfer mode. Others are omitted due to ambiguity. For
+   example ".hlp", and ".ini" are generally binary types in Windows but
+   text types everywhere else.
+
+     NOTE: ".doc", used for decades to denote plain-text documentation
+     files, now more often than not denotes a Microsoft Word Document,
+     so ".doc" is now considered a binary type since it does less harm
+     to transfer a plain-text document in binary mode than it does to
+     transfer an MS Word file in text mode (except when IBM mainframes
+     are involved!)
+
+     ANOTHER NOTE: ".com" files are binary in DOS-like operating
+     systems, but they are text (DCL command procedures) in VMS. VMS
+     C-Kermit sends .COM files in text mode; K95 sends them in binary
+     mode. If you download a .COM file from VMS to DOS or Windows, and
+     then upload it to another VMS system, be sure to use SEND /TEXT to
+     preserve its textness.
+
+   You can see the default pattern list by starting C-Kermit without its
+   initialization file (e.g. "kermit -Y") and using the SHOW PATTERNS
+   command. If you will be depending on this feature, be sure to examine
+   the list carefully in conjunction with the applications that you use.
+
+   The default pattern list does not take "backup files" into account
+   because (a) people usually don't want to transfer them; and (b) it
+   would make the pattern lists more than twice as long. For example, we
+   would need to include both *.txt and *.txt.~[0-9]*~ for ".txt" files,
+   and similarly for all the others. Instead, you can use SEND /NOBACKUP
+   (or SET SEND BACKUP OFF) to skip over all backup files.
+
+   Put your most commonly-used safe pattern declarations in your C-Kermit
+   customization file (ckermod.ini, .mykermrc, k95custom.ini, etc).
+
+   As noted, SET FILE PATTERNS is ON by default. Sometimes, however, it
+   is desirable, or necessary, to force files to be sent in a particular
+   mode, and often this must be done from the command line (e.g. when
+   using Kermit as a download helper in a Web browser like Lynx). The -V
+   command-line options is equivalent to SET FILE PATTERNS OFF and SET
+   TRANSFER MODE MANUAL. Example:
+
+  kermit -Vis oofa.txt
+
+   forces oofa.txt to be sent in binary mode, even though ".txt" might
+   match a text pattern.
+     _________________________________________________________________
+
+  4.4. File Permissions
+
+   "Permissions" refers to a code associated with a file that specifies
+   who is allowed to access it, and in what manner. For example, the
+   owner, the members of one or more groups, the system administrator,
+   and everybody else, might be allowed various combinations of Read,
+   Write, Append, Execute, or Listing access.
+
+   The permission code goes by different names on different platforms. In
+   UNIX, it might be called the filemode. In VMS, it is called the file
+   protection (or protection mask).
+
+   The comments in this section presently apply only to the UNIX and VMS
+   versions of C-Kermit, to which these features were added in version
+   7.0; the DOS, Windows, and OS/2 file systems embody no notions of
+   protection, and so MS-DOS Kermit and Kermit 95 do not send file
+   permissions, and ignore them when received.
+
+   The permissions for a received file are determined by a combination of
+   the file transfer mode (VMS-to-VMS transfers only), whether a file of
+   the same name exists already, whether permissions of the file are
+   received in the file attribute packet, and the setting of ATTRIBUTES
+   PROTECTION.
+
+   The default for ATTRIBUTES PROTECTION is ON. If no attributes are
+   received, the effect is the same as if attributes PROTECTION were OFF.
+
+   For VMS-to-VMS transfers, the default LABELED mode simply copies the
+   protection code from source to destination.
+     _________________________________________________________________
+
+    4.4.1. When ATTRIBUTES PROTECTION is OFF
+
+   If no file of the same name exists, system defaults determine the
+   permissions of the new file. Otherwise, the actions taken depend on
+   the current FILE COLLISION setting: BACKUP, OVERWRITE, RENAME, etc, as
+   documented in [463]Using C-Kermit. But now the new file (if it is
+   created at all) automatically inherits the permissions (mode bits) of
+   the existing file in a way that is appropriate for the platform.
+
+    4.4.1.1. Unix
+
+   All mode bits are inherited except the directory bit, since the
+   incoming file can not possibly be a directory. (In any case, it is not
+   possible to receive a file that has the same name as an existing
+   directory unless FILE COLLISION is set to RENAME).
+
+    4.4.1.2. VMS
+
+   Files with the same name as an existing file, transferred in modes
+   other than LABELED between VMS systems, inherit the protection of the
+   prior version.
+     _________________________________________________________________
+
+    4.4.2 When ATTRIBUTES PROTECTION is ON
+
+   File permissions can be conveyed as part of the file transfer process,
+   in accordance with the Kermit protocol definition. If the file sender
+   puts system-dependent and/or system-independent versions of the file
+   protection (permissions) into the Attribute (A) packet, the file
+   receiver can set the new file's permissions from them. Otherwise, the
+   permissions are set the same as for ATTRIBUTES PROTECTION OFF.
+
+   When the incoming A packet contains system-dependent permissions, the
+   file receiver checks to see if the sender has the same system ID (e.g.
+   both the sending and receiving systems are UNIX, or both are VMS); if
+   so, it decodes and uses the system-dependent permissions; otherwise it
+   uses the generic ones (if any) and applies them to the owner field,
+   setting the other fields appropriately as described in the following
+   sections.
+
+   Setting the incoming file's protection from the A packet is controlled
+   by SET ATTRIBUTES PROTECTION (or PERMISSION), which is ON by default,
+   and its status is displayed by SHOW ATTRIBUTES.
+
+   The main benefit of this feature is to not have to "chmod +x" an
+   executable file after transfer from UNIX to UNIX. Its cross-platform
+   benefits are less evident, perhaps to retain the status of the Unix
+   'x' bit on a VMS system, for subsequent transfer back to a Unix
+   system.
+     _________________________________________________________________
+
+    4.4.2.1. System-Specific Permissions
+
+   System-specific file permissions are used when the two Kermit programs
+   recognize each other as running on the same type of system. For
+   example, both are running under some form of UNIX (it doesn't matter
+   which UNIX variation -- HP-UX, Solaris, AIX, etc -- all use the same
+   scheme for file permissions); or both are running under VMS (even if
+   one is on an Alpha and the other on a VAX, and/or one is old and the
+   other is new).
+
+    4.4.2.1.1. UNIX
+
+   UNIX supports three categories of users, File Owner, Group, and World,
+   and three types of file access permission: Read, Write, and Execute.
+   Thus, a UNIX file's permissions are expressed in 9 bits.
+
+   The system-dependent permission string for UNIX is a 3-digit octal
+   string, the low-order 9 bits of the st_mode member of the stat struct;
+   we deliberately chop off the "file format" bits because they are not
+   permissions, nor do we convey the setuid/setgid bits, lock bit, sticky
+   bit, etc.
+
+    4.4.2.1.2. VMS
+
+   VMS supports four categories of users, System, File Owner, Group, and
+   World, and four types of file access permission: Read, Write, Execute,
+   and Delete. Thus, a VMS file's permissions are expressed in 16 bits.
+
+   The system-dependent protection string for VMS is a 4-digit
+   hexadecimal string, corresponding to the internal-format protection
+   word of the file (RWED for each of World,Group,Owner,System). A new
+   file normally gets all 16 protection bits from the original file of
+   the same name.
+
+   Note: VMS-to-VMS transfers take place in LABELED mode when the two
+   C-Kermits recognize each other's platform as VMS (unless you have
+   disabled LABELED-mode transfers). In this case, all of a file's
+   attributes are preserved in the transfer and the protection mask (and
+   other information) is taken from the file's internal information, and
+   this takes precedence over any information in the Attribute packets.
+   You can defeat the automatic switching into LABELED mode (if you want
+   to) with SET TRANSFER MODE MANUAL.
+     _________________________________________________________________
+
+    4.4.2.2. System-Independent Permissions
+
+   The system-independent ("generic") protection is used when the system
+   IDs of the two Kermit programs do not agree (e.g. one is UNIX, the
+   other is VMS). The generic protection attribute includes the following
+   permissions (not all are applicable to every file system): Read,
+   Write, Append, Execute, Delete, Search. The generic permissions are
+   derived from the owner permissions of the source file, thus, a Unix
+   'w' permission becomes VMS Write,Delete.
+
+   The Owner field of the new file's permissions is set from the incoming
+   generic protection attribute.
+
+   In UNIX, the Group and World permissions are set according to your
+   umask, except that execute permission is NOT set in these fields if it
+   was not also set in the generic protection (and consequently, is set
+   in the Owner field).
+
+   In VMS, the System, Group, and World permissions are set according to
+   the process default file permission (as shown in VMS by SHOW
+   PROTECTION), except that no permissions are allowed in these fields
+   that are not included in the generic permissions.
+
+   Note that the VMS and UNIX interpretations of Execute permission are
+   not identical. In UNIX, a file (binary executable, shell script, etc)
+   may not be executed unless it has Execute permission, and normally
+   files that are not intended for execution do not have Execute
+   permission. In VMS, Read permission implicitly supplies Execute
+   capability. Generally files that have Read permission also have
+   explicit Execute permission, but files (binary executables, DCL
+   command procedures) that have Read permission and not Execute
+   permission can still be executed.
+     _________________________________________________________________
+
+  4.5. File Management Commands
+
+    4.5.1. The DIRECTORY Command
+
+   Prior to C-Kermit 7.0, the DIRECTORY command always ran an external
+   system command (such as "ls" on UNIX) or program to product the
+   directory listing. This had certain advantages, mostly that you could
+   include system-dependent options for customized listings, e.g. on
+   UNIX:
+
+  dir -lt c* | more
+
+   or in VMS:
+
+  directory /size/date/protection/except=*.obj oofa.*;0
+
+   This approach, however, carries some disadvantages: C-Kermit can't
+   return SUCCESS or FAILURE status for (e.g.) "dir foo" according to
+   whether the file "foo" exists; and it runs an inferior process, which
+   might be a problem in some environments for resource and/or security
+   reasons, and won't work at all in a "nopush" environment (e.g. one in
+   which C-Kermit is configured to forbid access to exterior commands and
+   programs, e.g. in a VMS "captive account").
+
+   In C-Kermit 7.0 on VMS and UNIX, and in K95 1.1.19 and later, the
+   DIRECTORY command is internal to Kermit. It can be run in a "nopush"
+   environment and returns SUCCESS or FAILURE status appropriately. In
+   UNIX it prints all dates and times in a consistent way (unlike ls). In
+   VMS it prints precise file sizes, rather than "blocks". It offers
+   several formatting and other options, but it is not necessarily more
+   flexible than the corresponding external commands or programs (the
+   UNIX "ls" program, the VMS "directory" command). The syntax is:
+
+   DIRECTORY [ switch [ switch [ ... ] ] ] [ filespec ]
+
+   If no filespec is given, all files in the current directory are
+   listed.
+
+   Optional switches include all the standard file-selection switches
+   presented in [464]Section 1.5.4, plus:
+
+   /ALL
+          Show both regular files and directories; this is the default.
+
+   /ARRAY:x
+          Instead of displaying a directory listing, put the files that
+          would have been shown (based on the filespec and other
+          selection switches) in the given array. The array need not (and
+          should not) be predeclared; if the array already exists, it is
+          destroyed and reused. The array name can be a single letter,
+          like "a", or any fuller form, such as "&a", "\&a", "\&a[]",
+          etc. If the /ARRAY switch is included, the following other
+          switches are ignored: /BRIEF, /VERBOSE, /HEADING, /PAGE,
+          /ENGLISHDATE, /ISODATE, /XFERMODE, /MESSAGE, /SORT, /REVERSE,
+          /ASCENDING. In other words, only file selection switches are
+          meaningful with /ARRAY: /FILES, /DIRECTORIES, /ALL, /DOTFILES,
+          /NOBACKUP, /RECURSIVE, /SMALLER, /LARGER, /AFTER, /BEFORE,
+          /EXCEPT, etc. The resulting array has the number of files (n)
+          as its 0th element, and the filenames in elements 1 through n
+          Example:
+
+  dir /array:&a /files /nobackup /after:19990101 /larger:10000 [ab]*
+  show array &a
+
+   /FILES
+          Only show regular files.
+
+   /DIRECTORIES
+          Only show directories.
+
+   /BACKUP
+          In UNIX, OS-9, K-95, and other versions that support SET FILE
+          COLLISION BACKUP and create backup files by appending .~n~ to
+          the filename (where "n" is a number), /BACKUP means to include
+          these files in directory listings. This is the default.
+
+   /NOBACKUP
+          This is the opposite of /BACKUP: that is, do not include backup
+          files in the listing.
+
+   /BRIEF
+          List filenames only; use a compact format, as many filenames as
+          will fit across the screen (based on the longest name). A brief
+          listing is always sorted alphabetically.
+
+   /VERBOSE
+          List one file per line, and include date, size, and (in UNIX
+          only) permissions of each file. This is the opposite of /BRIEF,
+          and is the default.
+
+   /PAGE
+          Pause at the end of each screenful and give a "more?" prompt,
+          even if SET COMMAND MORE-PROMPTING is OFF.
+
+   /NOPAGE
+          Don't pause at the end of each screenful and give a "more?"
+          prompt, even if SET COMMAND MORE-PROMPTING is ON. If neither
+          /PAGE or /NOPAGE is given, paging is according to the
+          prevailing COMMAND MORE-PROMPTING setting (which can be
+          displayed with SHOW COMMAND).
+
+   /ENGLISHDATE
+          Show dates in dd-mmm-yyyy format; mmm is the first three
+          letters of the English month name.
+
+   /ISODATE
+          Show dates in yyyy-mm-dd format; mm is the month number, 1-12.
+          This is the opposite of /ENGLISHDATE, and is the default.
+
+   /HEADINGS
+          Print a heading before the listing and a summary at the end.
+
+   /NOHEADINGS
+          Don't print a heading before the listing or a summary at the
+          end. This is the opposite of /HEADINGS, and is the default.
+
+   /XFERMODE
+          Only in Kermit programs that support SET FILE PATTERNS. If this
+          switch is included, and the filename matches any FILE
+          BINARY-PATTERN ([465]Section 4.3), "(B)" is printed after the
+          filename; otherwise, if it matches a FILE TEXT-PATTERN, "(T)"
+          is printed.
+
+   /NOXFERMODE
+          Don't display transfer-mode indicators. This is the opposite of
+          /XFERMODE and is the default.
+
+   /RECURSIVE
+          Show files not only in the given directory, but also in its
+          subdirectories (if any), their subdirectories, etc.
+
+   /NORECURSIVE
+          Don't show files in subdirectories. This is the opposite of
+          /RECURSIVE, and is the default.
+
+   /MESSAGE:text
+          This lets you specify a short text string to be appended to the
+          end of each directory listing line (a space is supplied
+          automatically). If the text contains any spaces, enclose it in
+          braces, e.g. /MESSAGE:{two words}.
+
+   /NOMESSAGE
+          Don't append any message to the end of each directory listing
+          line (default).
+
+   /SORT:[{NAME,SIZE,DATE}]
+          Sort the listing by name, size, or date. If the /SORT switch is
+          given but the "sort-by" keyword is omitted, the listing is
+          sorted by name. /SORT:NAME /ASCENDING (alphabetic sort by name)
+          is the default.
+
+   /NOSORT
+          Don't sort the listing. Files are listed in whatever order they
+          are supplied by the operating system, e.g. inode order in UNIX.
+
+   /REVERSE
+          If the /SORT switch is given, reverse the order of the sort.
+          Synonym: /DESCENDING.
+
+   /ASCENDING
+          If the /SORT switch is given, sort the listing in normal order.
+          This is the opposite of /REVERSE and is the default.
+
+   Note that most of the DIRECTORY-specific switches come in pairs, in
+   which one member of a pair (e.g. /NOHEADINGS) is the opposite of the
+   other (e.g. /HEADINGS).
+
+   If you always want to use certain options, you can set them with the
+   SET OPTIONS DIRECTORY command ([466]Section 1.5.5). Use SHOW OPTIONS
+   to list the options currently in effect. To make the desired options
+   apply every time you run C-Kermit, put a SET OPTIONS DIRECTORY command
+   in your C-Kermit customization file, specifying the desired options.
+   Options set in this manner apply to every subsequent DIRECTORY
+   command. Of course, if you include switches in a DIRECTORY command,
+   these override any defaults, built-in or custom. Example:
+
+  DIRECTORY            ; Use "factory defaults"
+  SET OPTIONS DIRECTORY /SORT:SIZE /REVERSE /HEADINGS  ; Customize defaults
+  DIRECTORY            ; Use customized defaults
+  DIR /SORT:NAME       ; Override customized default SORT key
+  SET OPT DIR /RECURS  ; Add /RECURSIVE to customized defaults
+  DIR /ASCEND          ; Override customized default SORT order
+
+   Notes:
+
+     * Only a single sort key is supported; there is presently no way to
+       have multiple sort keys.
+     * If the /BRIEF switch is given, all other switches (except
+       /[NO]RECURSIVE, /[NO]DOTFILES, /DIRECTORIES, /FILES, and /ALL) are
+       ignored.
+     * /SORT:anything gives incorrect results if any files have lengths
+       greater than 10 digits (i.e. that are more than 9999999999 bytes
+       long, i.e. if they are 10GB or more in size) because the overlong
+       length field causes the date and name fields to be misaligned.
+     * /SORT:NAME is redundant in VMS since VMS returns filenames in
+       alphabetic order anyway.
+     * /SORT:NAME ignores alphabetic case on platforms where case does
+       not matter in filenames, but this works only for unaccented Roman
+       letters A-Z.
+     * /SORT:NAME is currently based on code values, and so works fine
+       for ASCII, but will probably produce unexpected results for files
+       with non-ASCII or 8-bit characters in their names. (Locale-based
+       sorting raises rather significant issues of portability, size,
+       performance, etc.)
+     * /SORT:DATE works right only for ISO-format dates, not English
+       ones.
+     * /SORT:SIZE sorts the size field lexically. On some platforms (e.g.
+       Windows), the size of a directory file is listed as "<DIR>" rather
+       than as a number; in this case, the "<DIR>" files are gathered at
+       the end (or beginning, depending on the sort order) of the
+       listing.
+     * /RECURSIVE is accepted but ignored in AOS/VS. Use the normal
+       system-specific filespec notation, e.g. "dir #.txt".
+     * /RECURSIVE has no affect when a full, absolute pathname is given;
+       e.g. "dir /recursive /tmp/foo" (where "foo" is a regular file)
+       only shows the "/tmp/foo" file. If you want to see all "foo" files
+       in the /tmp tree, do "cd /tmp" and then "dir /recursive foo".
+     * If a file size of -1 is shown, or date-time of 0000-00-00
+       00:00:00, this means the file was located, but access to
+       information about the file was denied to C-Kermit.
+     * In VMS, if FOO.DIR;1 is a directory within your current directory,
+       "directory foo" and "directory [.foo]" list the files in the
+       [.FOO] subdirectory, but "directory foo.dir" lists the directory
+       file itself; similarly for "*.dir" versus "[.*]", etc.
+     * In UNIX, if "foo" is a directory within your current directory,
+       "directory foo" lists the files in the foo directory. If you want
+       to list the foo directory file itself, put an asterisk at the end:
+       "dir foo*".
+
+   Hint: How to find the biggest files in a directory tree:
+
+  cd xxx ; (root of tree)
+  directory /sort:size /recursive /reverse /dotfiles /page
+
+   Another hint: If you often use several different directory-listing
+   formats, define macro shortcuts for them:
+
+  DEFINE WD DIRECTORY /SORT:DATE /REVERSE \%*  ; Reverse chronological order
+  DEFINE SD DIRECTORY /SORT:SIZE /REVERSE \%*  ; Reverse order of size
+  DEFINE ND DIRECTORY /SORT:NAME /ASCEND \%*   ; Alphabetical by name
+  DEFINE DL DIR /DIR /SORT:NAME /ASCEND \%*    ; Alphabetical directory list
+
+   Put these definitions in your C-Kermit customization file. Note that
+   "\%*" ([467]Section 7.5) in these definitions lets you include other
+   switches in your macro invocations, e.g.:
+
+  wd /headings *.txt
+
+   Of course you can still access your external directory listing program
+   by using RUN or "!", e.g. in VMS:
+
+  run directory /size/date/protection/except=*.obj oofa.*;0
+
+   or:
+
+  !dir /size/date/prot/exc=*.obj oofa.*;0
+
+   In UNIX, use "!ls" or just "ls" (which is a special synonym for
+   "!ls").
+     _________________________________________________________________
+
+    4.5.2. The CD and BACK Commands
+
+   In C-Kermit 7.0, the CD command has a new friend, the BACK command.
+   BACK means "CD to my previous current directory". A second BACK brings
+   you back to where you were before the first one; thus successive BACK
+   commands switch back and forth between two directories.
+
+    4.5.2.1. Parsing Improvements
+
+   The CD command, as well as other commands that parse a directory name,
+   were changed in 7.0 to provide all the expected functions: completion
+   on Tab or Esc, directory-name lists on ?, etc. Other affected commands
+   include SET SERVER GET-PATH, SET TEMP-DIRECTORY, SET FILE
+   DOWNLOAD-DIRECTORY, and SPACE. CD and REMOTE CD also now work with
+   logical names.
+
+   In VMS, the situation is a bit complicated since a directory name can
+   look like "DEV:", "[FOO.BAR]", "DEV:[FOO.BAR]", "[FOO]BAR.DIR;1", etc.
+   Completion and ?-help might not always work, but they do in many
+   cases. Examples:
+
+  cd ?           Lists all subdirectories of the current directory
+  cd []?         Ditto
+  cd k?          Ditto, but only those starting with K
+  cd [foo]?      Lists all subdirectories of the [FOO] directory
+  cd [-]?        Lists all subdirectories of the superior directory
+  cd [--]?       Lists all subdirectories of the directory 2 levels up
+  cd [...]?      Lists all directories below the current one
+  cd [foo.?      Does not work.
+
+   C-Kermit allows all of the following in VMS:
+
+  cd bar         CD to subdirectory BAR of the current directory
+  cd .bar        Ditto
+  cd [.bar]      Ditto
+  cd bar.dir     etc...
+  cd bar.dir;
+  cd bar.dir;1
+  cd [foo.bar]
+  cd bar.baz     This can go more than 1 level deep...
+  cd dir:        (where logical name DIR is defined as [FOO.BAR])
+
+   As well as the following:
+
+  cd ..          Go up one level as in UNIX
+  cd .           The current directory
+  cd             My login directory
+
+   Note that "cd -" (go up one level) does not work as expected, because
+   "-" is Kermit's command continuation character. However, "cd [-]", and
+   "
+   cd {-}" have the desired effect (and so does "cd ..", which is easier
+   to type).
+     _________________________________________________________________
+
+    4.5.2.2. The CDPATH
+
+   The CD command in the UNIX, Windows, OS/2, and VMS versions of
+   C-Kermit, as of version 6.1 / 1.1.12, searches the CDPATH for the
+   given directory, if it is not absolute and if a CDPATH environment
+   variable is defined. Example (in UNIX ksh or bash):
+
+  $ export CDPATH=$HOME:$HOME/kermit:/tmp
+
+   Now if you give a "cd xxx" command, no matter what your current
+   directory is, if the "xxx" directory is not a subdirectory of your
+   current directory, then the xxx subdirectory of your home directory is
+   used or if that does not exist, then the xxx subdirectory of the
+   kermit subdirectory of your home directory is used or if that does not
+   exist, then /tmp/xxx is used. This is how the ksh "cd" command works,
+   and now the C-Kermit CD command works the same way.
+
+   In VMS, you can define CDPATH to be a list of directories that contain
+   actual directory delimiters, and/or logical names representing
+   directories, using commas to separate them, e.g.:
+
+  $ define cdpath [HOME],[SOMEOTHERDIR],[HOME.MISC]
+  $ define cdpath SYS$LOGIN:,DISK1:[HOME],DISK2:[SCRATCH.IVAN]
+
+   Example:
+
+  $ define cdpath SYS$LOGIN:,[IVAN],[OLAF],[OLGA.MISC]
+  $ kermit
+  DISK1:[OLGA] C-Kermit> cd blah
+
+   tries the BLAH subdirectory of the user's login directory, then
+   [OLGA.BLAH], [IVAN.BLAH], [OLAF.BLAH], and [OLGA.MISC.BLAH], in that
+   order, using the first one it finds, failing if it finds none.
+
+   In C-Kermit 7.0, you may also set the CDPATH from the Kermit prompt:
+
+   SET CD PATH path
+          Allows the CD PATH to be set from within C-Kermit.
+
+   SHOW CD shows the CD path and all other information relevant to the CD
+   command.
+     _________________________________________________________________
+
+    4.5.2.3. CD Messages
+
+   Whenever you change directory, you can have C-Kermit display a "Read
+   Me" file from the new directory automatically. The commands are:
+
+   SET CD MESSAGE { ON, OFF, FILE list }
+          ON enables this feature; OFF (the default) disables it. File
+          lets you specify the name of the "Read Me" file. A list of
+          names to look for can be given in the following format:
+
+  {{name1}{name2}{name3}{...}}
+
+          e.g.:
+
+  SET SERVER CD-MESSAGE FILE {{./.readme}{README.TXT}{READ.ME}}
+
+          The default list of CD-message files is system dependent.
+
+   SHOW CD shows your current directory, previous directory, CD path, and
+   CD message info.
+     _________________________________________________________________
+
+    4.5.3. Creating and Removing Directories
+
+   The MKDIR command now allows you to create multiple directories at
+   once:
+
+  C-Kermit> mkdir a/b/c/d
+
+   creates the directory a in the current directory (if it doesn't exist
+   already), and then creates subdirectory b in the a directory (if it
+   didn't exist already), and so on.
+
+   If you use MKDIR to try to create a directory that already exists,
+   C-Kermit will print a warning ("?Directory already exists"), but the
+   MKDIR command will still succeed. If you want to avoid the warning
+   message, use IF DIRECTORY first to check if the directory already
+   exists.
+
+   The RMDIR command, however, will not remove more than one directory,
+   nor will it remove a directory that contains any files. (There is, as
+   yet, no RMDIR /RECURSIVE command, although one might be added later.)
+
+   In VMS, these commands (like CD) are more forgiving of your syntax
+   than is the DCL command shell; "mkdir oofa" is equivalent to "mkdir
+   [.oofa]" and so on. Also in VMS, you'll find that C-Kermit's RMDIR
+   command is easier than deleting a directory in DCL, since it
+   automatically first gives it owner delete permission if you are the
+   owner.
+     _________________________________________________________________
+
+    4.5.4. The DELETE and PURGE Commands
+
+   The DELETE command now offers a selection of switches, and has a new
+   companion, the PURGE command. First, DELETE:
+
+   DELETE [ switches... ] filespec
+          Deletes the file or files that match the filespec, which may
+          contain wildcards ([468]Section 4.9).
+
+   Optional switches include the standard file-selection switches
+   presented in [469]Section 1.5.4, plus:
+
+   /ASK
+          Before deleting each file, ask permission interactively.
+          Answers are Yes or OK (delete the file), No (don't delete it),
+          or Quit (stop executing the DELETE command).
+
+   /NOASK
+          Don't ask permission to delete each file.
+
+   /LIST
+          List each file and show whether it was deleted. Synonyms: /LOG,
+          /VERBOSE.
+
+   /NOLIST
+          Don't list files while deleting them. Synonyms: /NOLOG, /QUIET.
+
+   /HEADING
+          Print a heading and summary line.
+
+   /NOHEADING
+          Don't print a heading and summary line.
+
+   /PAGE
+          When listing, pause at the end of each screenful and give the
+          "More?" prompt. If you reply "n" (no), the DELETE command
+          terminates.
+
+   /SIMULATE
+          Do everything implied by the given switches and filespec,
+          except do not actually delete any files. This lets you preview
+          which files would be deleted; implies /LIST.
+
+   Now the PURGE command:
+
+   PURGE [ switches... ] [ filespec ]
+          (VMS only) Runs the DCL PURGE command. Switches and filespec,
+          if any, are passed directly to DCL without parsing or
+          verification. Deletes excess versions of the given (or all)
+          files. The rest of this section does not apply to VMS.
+
+   PURGE [ switches... ] [ filespec ]
+          (UNIX only) Deletes "backup files" that match the filespec,
+          which may contain wildcards ([470]Section 4.9). If no filespec
+          is given, all backup files in the current directory are
+          selected (subject to modification by any switches). Do not
+          include backup notation in the filespec.
+
+   Explanation:
+
+   To avoid destroying preexisting files when a new file arrives that has
+   the same name, C-Kermit backs up the old file by appending a "backup
+   number" to its name. In UNIX, the backup suffix consists of a period,
+   a tilde, a number, and another tilde. For example, if a file called
+   oofa.txt exists and a new oofa.txt file arrives, the original is
+   renamed to oofa.txt.~1~. If another oofa.txt file arrives, the
+   existing one is renamed to oofa.txt.~2~. And so on. This system is
+   compatible with the one used by EMACS. Thus over time, if you receive
+   a lot of files with C-Kermit or edit them with EMACS, backup files can
+   build up. The new PURGE command lets you clean out accumulated backup
+   files:
+
+   Optional switches include the standard file-selection switches
+   presented in [471]Section 1.5.4, plus all the switches listed above
+   for the DELETE command, plus:
+
+   /KEEP:n
+          Retains the n most recent (highest-numbered) backup files for
+          each file. For example, if oofa.txt, oofa.txt.~1~,
+          oofa.txt.~2~, oofa.txt.~10~, oofa.txt.~12~, and oofa.txt.~100~
+          exist, "purge /keep:2 oofa.txt" deletes oofa.txt.~1~,
+          oofa.txt.~2~, and oofa.txt.~10~, and keeps oofa.txt,
+          oofa.txt.~12~, and oofa.txt.~100~. If /KEEP is given without a
+          number, one (the highest numbered) backup file is kept.
+
+   CAUTION: The PURGE command should be used only when *.~*~ files truly
+   are backup files. This is the case for EMACS, and it is the DEFAULT
+   for C-Kermit. However, if C-Kermit's FILE COLLISION has been set to
+   RENAME, newly received files will look like backup files. In that
+   case, don't use the PURGE command or you'll be removing new files
+   rather than old ones. (Use SHOW FILE to find the FILE COLLISION
+   setting.)
+
+   The PURGE command is presently available only in UNIX. The command
+   succeeds if it deleted any files, or if it deleted no files but there
+   were no errors. It fails if it deleted no files and there were errors
+   (i.e. deletion was attempted but failed). In VMS, backup file versions
+   are handled automatically by the OS, and a PURGE command can be used
+   at the VMS prompt to clean them up.
+
+   If you want certain switches to be supplied automatically with each
+   DELETE or PURGE command, you can set them with SET OPTIONS
+   ([472]Section 1.5.5) and you can display any such settings with SHOW
+   OPTIONS. Of course you can override them on a per-command basis by
+   including switches in your PURGE or DELETE command.
+
+   Also see SET FILE COLLISION, SHOW FILE, SEND /NOBACKUP, SET SEND
+   BACKUP, and DIRECTORY /[NO]BACKUP.
+     _________________________________________________________________
+
+  4.6. Starting the Remote Kermit Server Automatically
+
+   As noted on pages 275-276 of [473]Using C-Kermit 2nd edition, you can
+   have Kermit send "kermit receive" commands automatically when it is in
+   local mode and you give a SEND or similar command, to start the remote
+   Kermit receiver in case it is not already started. The "kermit
+   receive" commands are specified by:
+
+  SET PROTOCOL KERMIT binary-receive-command text-receive-command
+
+   As of version 7.0, a Kermit protocol option has been added to send a
+   string to the host in advance of any Kermit packets when you give a
+   GET-class or REMOTE command. This will switch the remote C-Kermit into
+   the appropriate mode or, if the remote system is at a system command
+   (shell) prompt, execute the string on the remote system. The new
+   syntax of the SET PROTOCOL KERMIT command is:
+
+  SET PROTOCOL KERMIT [ s1 [ s2 [ s3 ] ] ]
+
+   where:
+
+       Default         Meaning
+  s1  {kermit -ir}     Remote "kermit receive in binary mode" command.
+  s2  {kermit -r}      Remote "kermit receive in text mode" command.
+  s3  {kermit -x}      Remote "start kermit server" command.
+
+   NOTE: If the remote Kermit is 6.0, the following are recommended for
+   fast startup and high-performance file transfer (see Appendix I in
+   [474]Using C-Kermit, second Edition, for command-line options):
+
+  s1   kermit -YQir   (Kermit receive binary, skip init file, fast.)
+  s2   kermit -YQTr   (Kermit receive text, skip init file, fast.)
+  s3   kermit -YQx    (Kermit server, skip init file, fast.)
+
+   If the remote is C-Kermit 7.0 or later, change the -x option (enter
+   server mode) to -O (uppercase letter O), which means "enter server
+   mode for One transaction only); this way, it is not stuck in server
+   after the transfer. Also note that the Q is redundant in version 7.0,
+   since fast Kermit protocol settings are now the default.
+
+   Note that in case the C-Kermit executable is called "wermit" or
+   "ckermit" you can change "kermit" in the strings above to "wermit" or
+   "ckermit" and C-Kermit 7.0 or later will recognize these as synonyms
+   for "kermit", in case it is at its command prompt when one of these
+   strings is sent to it.
+     _________________________________________________________________
+
+  4.7. File-Transfer Command Switches
+
+   Over the years, various new methods of transferring a file have
+   accumulated, until we had, in addition to the SEND command, also MOVE
+   (send and then delete), MAIL (send as email), REMOTE PRINT (send to be
+   printed), CSEND (send the output of a command), PSEND (send a part of
+   a file), BSEND (send in binary mode), RESEND (resume an interrupted
+   SEND), etc etc. Similarly: GET, REGET, CGET, RETRIEVE, and so on.
+
+   Not only is it confusing to have different names for these commands,
+   many of which are not real words, but this also does not allow all
+   combinations, like "send a file as mail, then delete it".
+
+   In C-Kermit 7.0, the SEND, GET, and RECEIVE commands were restructured
+   to accept modifier switches (switches are explained in [475]Section
+   1.5).
+     _________________________________________________________________
+
+    4.7.1. SEND Command Switches
+
+   Without switches, the SEND command still works exactly as before:
+
+  send oofa.txt      ; send a single file
+  send oofa.*        ; send multiple files
+  send oofa.txt x.x  ; send oofa.txt as x.x (tell receiver its name is x.x)
+  send               ; send from SEND-LIST
+
+   But now the following modifier switches may be included between "send"
+   and the filename. Zero, one, two, or more switches may be included in
+   any combination that makes sense. Switch names (such as /BINARY) can
+   be abbreviated, just like any other keywords. Most of these switches
+   work only when using Kermit protocol (/TEXT and /BINARY are the
+   exceptions).
+
+   /AFTER:date-time
+          Specifies that only those files modified (or, in VMS, created)
+          after the given date-time (see [476]Section 1.6) are to be
+          sent. Examples:
+
+  send /text /after:{2-Feb-1997 10:28:30} *.txt
+  send /text /after:\fdate(oofa.txt) *.txt
+
+          Synonym: /SINCE.
+
+   /ARRAY:arrayname
+          Specifies that instead of sending a file, C-Kermit is to send
+          the contents of the given array. Since an array does not have a
+          filename, you should include an /AS-NAME switch to specify the
+          name under which the array is to be sent (if you do not, the
+          name "_array_x_" is used, where 'x' is replaced by the array
+          designator). See [477]section 7.10 for array-name syntax. As
+          noted in that section, you can also include a range to have a
+          segment of the array sent, rather than the whole thing; for
+          example: "send /array:&a[100:199]". It is strongly recommended
+          that you accompany the /ARRAY switch with a /TEXT or /BINARY
+          switch to force the desired transfer mode, since otherwise the
+          various automatic mechanisms might switch to binary mode when
+          you really wanted text, or vice versa. In text mode a line
+          terminator is added to the end of each array element, but not
+          in binary mode. For details and examples see [478]Section
+          7.10.11.
+
+   /AS-NAME:text
+          Specifies "text" as the name to send the file under. You can
+          also still specify the as-name as the second filename on the
+          SEND command line. The following two commands are equivalent:
+
+  send oofa.txt oofa.new
+  send /as:oofa.new oofa.txt
+
+   /BEFORE:date-time
+          Specifies that only those files modified (or, in VMS, created)
+          before the given date-time ([479]Section 1.6) are to be sent.
+
+   /BINARY
+          Performs this transfer in binary mode without affecting the
+          global transfer mode, overriding not only the FILE TYPE and
+          TRANSFER MODE settings, but also the FILE PATTERN setting, but
+          for this SEND command only. In other words, SEND /BINARY means
+          what it says: send the file in binary mode, regardless of any
+          other settings. Example:
+
+  set file type text      ; Set global transfer mode to text
+  send /binary oofa.zip   ; Send a file in binary
+  send oofa.txt           ; This one is sent in text mode
+
+   /COMMAND
+          SEND /COMMAND is equivalent to CSEND ([480]Section 4.2.2) -- it
+          says to send 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. Examples:
+
+  send /command {grep Sunday oofa.txt} sunday.txt
+  send /as-name:sunday.txt /command {grep Sunday oofa.txt}
+  send /bin /command {tar cf - . | gzip -c} {!gunzip -c | tar xf -}
+
+   /DELETE
+          Deletes the file (or each file in the group) after it has been
+          sent successfully (but does not delete it if it was not sent
+          successfully). SEND /DELETE is equivalent to MOVE. Has no
+          effect when used with /COMMAND. Example:
+
+  send /delete *.log
+
+   /DOTFILES
+          (UNIX and OS-9 only) Normally files whose names begin with "."
+          are skipped when matching wildcards that do not also beging
+          with ".". Include /DOTFILES to force these files to be included
+          too.
+
+   /RECURSIVE
+          Descend the through the directory tree when locating files to
+          send. Automatically sets /PATHNAMES:RELATIVE. Explained in
+          [481]Section 4.11 .
+
+   /EXCEPT:pattern
+          See [482]Section 1.5.4.
+
+   /NOBACKUP
+          This means to skip backup files when sending, even if they
+          match the SEND file specification. This is equivalent to using
+          SEND /EXCEPT and including *.~[0-9]*~ in the exception list (or
+          *.~*~ if Kermit was built without pattern-matching support; see
+          [483]Section 4.9.1). Including this switch is equivalent to
+          giving SET SEND BACKUP OFF ([484]Section 4.0.6) prior to SEND,
+          except its effect is local to the SEND command with which it
+          was given.
+
+   /NODOTFILES
+          The opposite of /DOTFILES (q.v.)
+
+   /FILENAMES:{CONVERTED,LITERAL}
+          Use this switch to override the current global SET FILE NAMES
+          setting for this transfer only.
+
+   /FILTER:command
+          This specifies a filter to pass the file through before sending
+          it. See the [485]section on file-transfer pipes and filters.
+          The /FILTER switch applies only to the file-transfer command it
+          is given with; it does not affect the global SEND FILTER
+          setting, if any.
+
+   /IMAGE
+          VMS: Sends in image mode. Non-VMS: same as /BINARY.
+
+   /LABELED
+          VMS and OS/2 only: Sends in labeled mode.
+
+   /LARGER-THAN:number
+          Specifies that only those files that are longer than the given
+          number of bytes are to be sent.
+
+   /LISTFILE:filename
+          Specifies that the files to be sent are listed in a file with
+          the given filename. The file contains one filename per line.
+          These filenames are not checked in any way; each filename is
+          taken and does not use or depend on any Kermit-specific syntax.
+          In particular, backslashes are not treated specially, leading
+          and trailing spaces are not stripped, etc. However, if a
+          filename contains wildcards, they are expanded. Example: If a
+          file named files.txt contains the following lines:
+
+  blah.txt
+  oofa*
+  x.x
+
+          (but without leading or trailing spaces), then the C-Kermit
+          command "send /listfile:files.txt" will send the files
+          blah.txt, x.x, and all files whose names start with "oofa",
+          assuming the files exist and are readable. The /LISTFILE
+          switch, can, of course, be used with other switches when it
+          makes sense, for example, /EXCEPT, /BINARY, /AFTER, /SMALLER,
+          /MOVE-TO, /DELETE, /AS-NAME with a template, etc.
+
+   /MAIL:address
+          Sends the file as e-mail to the given address or addresses.
+          "send /mail:address filename" is equivalent to "mail filename
+          address". You can include multiple addresses separated by
+          commas. Examples:
+
+  send /mail:kermit-support@columbia.edu packet.log
+  send /mail:cmg,fdc,jrd oofa.txt
+
+          As with any switch argument, if the address or address list
+          contains any spaces, you must enclose it in braces. The format
+          of the addresses must agree with that understood by the
+          mail-sending program on the receiver's computer.
+
+   /MOVE-TO:directory-name
+          Specifies that after each (or the only) source file is sent
+          successfully, and ONLY if it is sent successfully, it should be
+          moved to the named directory. If the directory name contains
+          spaces, enclose it in braces. If the directory does not exist,
+          it is created if possible; if it can't be created, the command
+          fails and an error message is printed. Example:
+
+  send /text /move-to:/users/olga/backup/ *.txt
+
+   /NOT-AFTER:date-time
+          Specifies that only those files modified at or before the given
+          date and time are to be sent.
+
+   /NOT-BEFORE:date-time
+          Specifies that only those files modified at or after the given
+          date and time are to be sent.
+
+   /PATHNAMES:{OFF,ABSOLUTE,RELATIVE}
+          Use this switch to override the current global SET SEND
+          PATHNAMES setting for this transfer only. /PATHNAMES:ABSOLUTE
+          or RELATIVE also sets /FILENAMES:LITERAL (also for this
+          transfer only) since pathnames are not sent otherwise.
+
+   /RENAME-TO:text
+          Specifies that after the (or each) source file is sent
+          successfully, and ONLY if it is sent successfully, it should be
+          renamed to the name given. If the name contains spaces, enclose
+          it in braces. If a file group is being sent, then the "text"
+          must contain a variable reference such as \v(filename) (see
+          [486]Section 4.1). Example:
+
+  send /rename-to:ok_\v(filename) *.*
+
+          This sends each file in the current directory and if it was
+          sent successfully, changes its name to begin with "ok_".
+
+   /SMALLER-THAN:number
+          Specifies that only those files that are smaller than the given
+          number of bytes are to be sent.
+
+   /SUBJECT:text
+          Subject for email. Actually, this is just a synonym for
+          /AS-NAME. If the text includes spaces, you must enclose it in
+          braces. If you don't specify a subject (or as-name), the name
+          of the file is used as the subject. Example:
+
+  send /mail:kermit-support@columbia.edu /subj:{As requested} packet.log
+
+   /PRINT:options
+          Sends the file to be printed, optionally specifying options for
+          the printer. Equivalent to REMOTE PRINT filename options.
+          Examples:
+
+  send /print oofa.txt              ; No options.
+  send /print:/copies=3 oofa.txt    ; "/copies=3" is a VMS PRINT switch.
+  send /print:-#3 oofa.txt          ; "-#3" is a UNIX lpr switch.
+
+   /PROTOCOL:name
+          Uses the given protocol to send the file (Kermit, Zmodem, etc)
+          for this transfer without changing global protocol. Only
+          available in Kermit 95, UNIX, and OS-9. Example:
+
+  set protocol kermit               ; Set global protocol
+  send /proto:zmodem /bin oofa.zip  ; Send just this file with Zmodem
+  send oofa.txt                     ; This file is sent with Kermit
+
+   /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 to RESEND. Recovery only works in binary
+          mode; SEND /RECOVER and RESEND include an implied /BINARY
+          switch. Even then, recovery will successful only if (a) the
+          original (interrupted) transfer was also in binary mode, or (b)
+          if it was in text mode, the two Kermit programs run on
+          platforms where text-mode transfers are not length-changing.
+
+   /STARTING:number
+          Starts sending the file from the given byte position. SEND
+          /STARTING:n filename is equivalent to PSEND filename n.
+
+   /TEXT
+          Performs this transfer in text mode without affecting the
+          global transfer mode, overriding not only the FILE TYPE and
+          TRANSFER MODE settings, but also the FILE PATTERN setting, for
+          this SEND command only. In other words, SEND /TEXT really send
+          the file in text mode, regardless of any other settings or
+          negotiations.
+
+   About mail... Refer to [487]Section 4.7.1. The same rules apply as for
+   file transfer. If you are mailing multiple files, you can't use an
+   as-name (in this case, a subject) unless it contains replacement
+   variables like \v(filenum). For example, if you:
+
+  send /mail:somebody@xyz.com *.txt
+
+   Then each file will arrive as a separate email message with its name
+   as the subject. But if you:
+
+  send /mail:somebody@xyz.com /subject:{Here is a file} *.txt
+
+   Then each file message will have the same subject, which is probably
+   not what you want. You can get around this with constructions like:
+
+  send /mail:somebody@xyz.com /subject:{Here is \v(filename)} *.txt
+
+   which embed the filename in the subject.
+
+   The MOVE, CSEND, MAIL, and RESEND commands now also accept the same
+   switches. And the switches are also operative when sending from a
+   SEND-LIST (see [488]Using C-Kermit, 2nd Ed, pp.191-192), so, for
+   example, it is now possible to SEND /PRINT or SEND /MAIL from a
+   SEND-LIST.
+
+   The MSEND and MMOVE commands also take switches, but not all of them.
+   With these commands, which take an arbitrary list of filespecs, you
+   can use /BINARY, /DELETE, /MAIL, /PRINT, /PROTOCOL, /QUIET, /RECOVER,
+   and /TEXT (and /IMAGE or /LABELED, depending on the platform). MMOVE
+   is equivalent to MSEND /DELETE. (If you want to send a group of files,
+   but in mixed transfer modes with per-file as-names, use ADD SEND-LIST
+   and then SEND.)
+
+   The MSEND/MMOVE switches come before the filenames, and apply to all
+   of them:
+
+  msend /print /text *.log oofa.txt /etc/motd
+
+   If you type any of these commands (SEND, CSEND, MSEND, etc) followed
+   by a question mark (?), you will see a list of the switches you can
+   use. If you want to see a list of filenames, you'll need to type
+   something like "send ./?" (UNIX, OS/2, Windows, etc), or "send []?"
+   (VMS), etc. Of course, you can also type pieces of a filename
+   (anything that does not start with "/") and then "?" to get a list of
+   filenames that start that way; e.g. "send x.?" still works as before.
+
+   In UNIX, where "/" is also the directory separator, there is usually
+   no ambiguity between a fully-specified pathname and a switch, except
+   when a file in the root directory has the same name as a switch (as
+   noted in [489]Section 1.5):
+
+  send /etc/motd                        ; Works as expected
+  send /command                         ; ???
+
+   The second example interprets "/command" as a switch, not a filename.
+   To send a file actually called "command" in the root directory, use:
+
+  send {/command}
+
+   or other system-dependent forms such as //command, /./command,
+   c:/command, etc, or cd to / and then "send command".
+     _________________________________________________________________
+
+    4.7.2. GET Command Switches
+
+   Without switches, the GET command still works about the same as
+   before:
+
+  get oofa.txt                          ; GET a single file
+  get oofa.*                            ; GET multiple files
+
+   However, the mechanism for including an "as-name" has changed.
+   Previously, in order to include an as-name, you were required to use
+   the "multiline" form of GET:
+
+  get
+  remote-filespec
+  local-name
+
+   This was because the remote filespec might contain spaces, and so
+   there would be no good way of telling where it ended and where the
+   local name began, e.g:
+
+  get profile exec a foo
+
+   But now since we can use {braces} for grouping, we don't need the
+   multiline GET form any more, and in fact, support for it has been
+   removed. If you give a GET command by itself on a line, it fails and
+   an error message is printed. The new form is:
+
+   GET [ switches... ] remote-name [ local-name ]
+          Ask the server to send the file whose name is remote-name. If
+          the optional local-name is given, store it locally under this
+          name. If the remote-name or local-name contains spaces, they
+          must be enclosed in braces:
+
+  get {profile exec a} foo
+  get oofa.txt {~/My Files/Oofa text}
+
+   If you want to give a list of remote file specifications, use the MGET
+   command:
+
+   MGET [ switches... ] remote-name [ remote-name [ remote-name ... ] ]
+          Ask the server to send the files whose names are given.
+
+   Now you can also include modifier switches between GET or MGET and the
+   remote-name; most of the same switches as SEND:
+
+   /AS-NAME:text
+          Specifies "text" as the name to store the incoming file under.
+          (This switch is not available for MGET.) You can also still
+          specify the as-name as the second filename on the GET command
+          line. The following two commands are equivalent:
+
+  get oofa.txt oofa.new
+  get /as:oofa.new oofa.txt
+
+   /BINARY
+          Tells the server to send the given file(s) in binary mode
+          without affecting the global transfer mode. Example:
+
+  set file type text      ; Set global transfer mode to text
+  get /binary oofa.zip    ; get a file in binary mode
+  get oofa.txt            ; This one is transferred in text mode
+
+          Or, perhaps more to the point:
+
+  get /binary foo.txt     ; where "*.txt" is a text-pattern
+
+          This has the expected effect only if the server is C-Kermit 7.0
+          or later or K95 1.1.19 or later.
+
+   /COMMAND
+          GET /COMMAND is equivalent to CGET ([490]Section 4.2.2) -- it
+          says to receive 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. Examples:
+
+  get /command sunday.txt {grep Sunday oofa.txt}
+  get /command /as-name:{grep Sunday oofa.txt} sunday.txt
+  get /bin /command {!gunzip -c | tar xf -} {tar cf - . | gzip -c}
+
+   /DELETE
+          Asks the Kermit server to delete the file (or each file in the
+          group) after it has been transferred successfully (but not to
+          delete it if it was not sent successfully). GET /DELETE is
+          equivalent to RETRIEVE. Example:
+
+  get /delete *.log
+
+   /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 upon arrival. To specify
+          multiple patterns (up to 8), use outer braces around the group,
+          and inner braces around each pattern:
+
+  /EXCEPT:{{pattern1}{pattern2}...}
+
+          See the description of SEND /EXCEPT in [491]Section 4.7.1 for
+          examples, etc. Refusal is accomplished using the Attribute
+          Rejection mechanism (reason "name"), which works only when
+          Attribute packets have been successfully negotiated.
+
+   /FILENAMES:{CONVERTED,LITERAL}
+          Use this switch to override the current global SET FILE NAMES
+          setting for this transfer only.
+
+   /FILTER:command
+          This specifies a filter to pass the incoming file through
+          before writing to disk. See the [492]section on file-transfer
+          pipes and filters. The /FILTER switch applies only to the
+          file-transfer command it is given with; it does not affect the
+          global RECEIVE FILTER setting, if any.
+
+   /IMAGE
+          VMS: Transfer in image mode. Non-VMS: same as /BINARY.
+
+   /LABELED
+          VMS and OS/2 only: Specifies labeled transfer mode.
+
+   /MOVE-TO:directory
+          This tells C-Kermit to move each file that is successfully
+          received to the given directory. Files that are not
+          successfully received are not moved. By default, files are not
+          moved.
+
+   /PATHNAMES:{OFF,ABSOLUTE,RELATIVE,AUTO}
+          Use this switch to override the current global SET RECEIVE
+          PATHNAMES setting for this transfer only. /PATHNAMES:ABSOLUTE
+          or RELATIVE also sets /FILENAMES:LITERAL (also for this
+          transfer only) since incoming pathnames would not be treated as
+          pathnames otherwise. See [493]Section 4.10.
+
+   /QUIET
+          When sending in local mode, this suppresses the file-transfer
+          display.
+
+   /RECOVER
+          Used to recover from a previously interrupted transfer; GET
+          /RECOVER is equivalent to REGET. Recovery only works in binary
+          mode; SEND /RECOVER and RESEND include an implied /BINARY
+          switch. Even then, recovery will successful only if (a) the
+          original (interrupted) transfer was also in binary mode, or (b)
+          if it was in text mode, the two Kermit programs run on
+          platforms where text-mode transfers are not length-changing.
+
+   /RECURSIVE
+          Tells the server that the GET file specification applies
+          recursively. This switch also automatically sets
+          /PATHNAMES:RELATIVE in both the server AND the client. When
+          used in conjunction with /DELETE, this "moves" a directory tree
+          from the server's computer to the client's computer (except
+          that only regular files are deleted from the server's computer,
+          not directories; thus the original directories will be left,
+          but will contain no files). Note that all servers that support
+          /RECURSIVE do not necessarily do so in combination with other
+          switches, such as /RECOVER. (Servers that do include C-Kermit
+          7.0 and later, K95 1.1.19 and later.)
+
+   /RENAME-TO:string
+          This tells C-Kermit to rename each file that is successfully
+          received to the given string. Files that are not successfully
+          received are not renamed. By default, files are not renamed.
+          The string can be a literal string, which is appropriate when
+          only one file is being received, or it can contain one or more
+          variables that are to be evaluated at the time each file is
+          received, such as \v(filename), \v(filenumber), \v(ntime),
+          \v(pid), \v(user), etc. WARNING: if you give a literal string
+          and more than one file arrives, each incoming file will be
+          given the same name (but SET FILE COLLISION BACKUP or RENAME
+          can be used to keep the incoming files from overwriting each
+          other).
+
+   /TEXT
+          Tells the server to perform this transfer in text mode without
+          affecting its global transfer mode. See /BINARY for additional
+          info.
+
+   The /MAIL and /PRINT options are not available (as they are for SEND),
+   but you can use /COMMAND to achieve the same effect, as in these UNIX
+   examples:
+
+  get /command oofa.txt {mail kermit@columbia.edu}
+  get /command oofa.txt lpr
+
+   In OS/2 or Windows, you can GET and print like this:
+
+  get oofa.txt prn
+
+   The CGET, REGET, RETRIEVE commands also accept the same switches as
+   GET. CGET automatically sets /COMMAND; REGET automatically sets
+   /RECOVER and /BINARY, and RETRIEVE automatically sets /DELETE.
+     _________________________________________________________________
+
+    4.7.3. RECEIVE Command Switches
+
+   Without switches, the RECEIVE command still works as before:
+
+  receive            ; Receives files under their own names
+  receive /tmp       ; Ditto, but into the /tmp directory
+  r                  ; Same as "receive"
+  receive foo.txt    ; Receives a file and renames to foo.txt
+
+   Now you can also include modifier switches may be included between
+   "receive" and the as-name; most of the same switches as GET:
+
+   /AS-NAME:text
+          Specifies "text" as the name to store the incoming file under.
+          You can also still specify the as-name as a filename on the
+          command line. The following two commands are equivalent:
+
+  r oofa.new
+  r /as:oofa.new
+
+   /BINARY
+          Performs this transfer in binary mode without affecting the
+          global transfer mode. NOTE: This does not override the incoming
+          filetype (as it does with GET), so this switch is useful only
+          if ATTRIBUTE TYPE is OFF, or if the other Kermit does not send
+          a TYPE (text or binary) attribute. In any case, it has no
+          affect whatsoever on the file sender.
+
+   /COMMAND
+          RECEIVE /COMMAND is equivalent to CRECEIVE ([494]Section 4.2.2)
+          -- it says to receive 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.
+
+  r /command {grep Sunday oofa.txt}
+  r /command /as-name:{grep Sunday oofa.txt}
+  r /bin /command {tar cf - . | gzip -c}
+
+   /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 upon arrival. To specify
+          multiple patterns (up to 8), use outer braces around the group,
+          and inner braces around each pattern:
+
+  /EXCEPT:{{pattern1}{pattern2}...}
+
+          See the description of SEND /EXCEPT in [495]Section 4.7.1 for
+          examples, etc. Refusal is accomplished using the Attribute
+          Rejection mechanism (reason "name"), which works only when
+          Attribute packets have been successfully negotiated.
+
+   /FILENAMES:{CONVERTED,LITERAL}
+          Use this switch to override the current global SET FILE NAMES
+          setting for this transfer only.
+
+   /FILTER:command
+          This specifies a filter to pass the incoming file through
+          before writing to disk. See the [496]section on file-transfer
+          pipes and filters. The /FILTER switch applies only to the
+          file-transfer command it is given with; it does not affect the
+          global RECEIVE FILTER setting, if any.
+
+   /IMAGE
+          VMS: Transfer in image mode. Non-VMS: same as /BINARY. See
+          comments under RECEIVE /BINARY.
+
+   /LABELED
+          VMS and OS/2 only: Specifies labeled transfer mode. See
+          comments under RECEIVE /BINARY.
+
+   /MOVE-TO:directory
+          This tells C-Kermit to move each file that is successfully
+          received to the given directory. Files that are not
+          successfully received are not moved. By default, files are not
+          moved.
+
+   /PATHNAMES:{ABSOLUTE,RELATIVE,OFF,AUTO}
+          Use this switch to override the current global SET RECEIVE
+          PATHNAMES setting for this transfer only. See [497]Section
+          4.10.
+
+   /RECURSIVE
+          When used with the RECEIVE command, /RECURSIVE is simply a
+          synonym for /PATHNAMES:RELATIVE.
+
+   /RENAME-TO:string
+          This tells C-Kermit to rename each file that is successfully
+          received to the given string. Files that are not successfully
+          received are not renamed. By default, files are not renamed.
+          The string can be a literal string, which is appropriate when
+          only one file is being received, or it can contain one or more
+          variables that are to be evaluated at the time each file is
+          received, such as \v(filename), \v(filenumber), \v(ntime),
+          \v(pid), \v(user), etc. WARNING: if you give a literal string
+          and more than one file arrives, each incoming file will be
+          given the same name (but SET FILE COLLISION BACKUP or RENAME
+          can be used to keep the incoming files from overwriting each
+          other).
+
+   /QUIET
+          When receiving in local mode, this suppresses the file-transfer
+          display.
+
+   /TEXT
+          Receives in text mode without affecting the global transfer
+          mode. See comments under RECEIVE /BINARY.
+
+   The /MAIL and /PRINT options are not available, but you can use
+   /COMMAND to achieve the same effect, as in these UNIX examples:
+
+  r /command {mail kermit@columbia.edu}
+  r /command lpr
+
+   In OS/2 or Windows, you can RECEIVE and print like this:
+
+  receive prn
+
+   The CRECEIVE command now also accepts the same switches.
+     _________________________________________________________________
+
+  4.8. Minor Kermit Protocol Improvements
+
+    4.8.1. Multiple Attribute Packets
+
+   C-Kermit 7.0 now sends more than one Attribute packet if a file's
+   attributes do not fit into a single packet of the negotiated length.
+   If a particular attribute (such as file creation date-time) does not
+   fit within the negotiated length (which will only happen when the
+   negotiated length is around 20 or less), that attribute is not sent at
+   all.
+
+    4.8.2. Very Short Packets
+
+   There are certain situations where extremely short packets must be
+   used; 20 or 30 bytes at most. This can happen when one or more devices
+   along the communication path have very small buffers and lack an
+   effective means of flow control. Examples are sometimes cited
+   involving radio modems.
+
+   When the maximum packet length is shorter than certain packets that
+   would be sent, those packets are either truncated or else broken up
+   into multiple packets. Specifically:
+
+    1. Parameter negotiation packets (I, S, and their ACKs) are truncated
+       to the negotiated length. Any parameters that do not fit are reset
+       to their default values. There is no provision in the Kermit
+       protocol for fragmentation and reassembly of parameter strings.
+    2. File header packets (containing the filename) are simply
+       truncated. There is no provision in the Kermit protocol for
+       fragmentation and reassembly of filenames.
+    3. Attribute packets are fragmented and reassembled as described in
+       4.8.1 without loss of data, except in case a field will not fit at
+       all in the negotiated length (the longest attribute is usually the
+       date and time of file creation/modification) because of the rule
+       that attributes may not be broken across packets.
+    4. Data packets and other packets are unaffected -- they can be as
+       short as they need to be, within reason.
+     _________________________________________________________________
+
+  4.9. Wildcard / File Group Expansion
+
+   "Wildcard" refers to the notation used in filenames to specify a group
+   of files by pattern matching.
+
+    4.9.1. In UNIX C-Kermit
+
+   Prior to C-Kermit 7.0, C-Kermit was capable of expanding wildcard
+   strings containing only the "metacharacters" '*' and '?':
+
+   *
+          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".
+
+   ?
+          Matches any single character. For example, "ck?.c" matches all
+          files whose names are exactly 5 characters long and start with
+          "ck" and end 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,
+          which is providing menus and file lists.
+
+   C-Kermit 7.0 adds the additional features that users of ksh, csh, and
+   bash are accustomed to:
+
+   [abc]
+          Square brackets enclosing a list of characters matches any
+          single character in the list. Example: ckuusr.[ch] matches
+          ckuusr.c and ckuusr.h.
+
+   [a-z]
+          Square brackets enclosing a range of characters; the 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 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 metacharacters, bracket
+          lists, or indeed, other lists of strings, but (when matching
+          filenames) they may not contain directory separators.
+
+          Thus, the metacharacters in filenames (and in any other field
+          that can be a pattern, such as the IF MATCH pattern, SEND or
+          GET exception lists, etc) are:
+
+ * ? [ {
+
+          And within braces only, comma (,) is a metacharacter.
+
+   To include a metacharacter in a pattern literally, precede it with a
+   backslash '\' (or two if you are passing the pattern to a macro).
+   Examples:
+
+  send a*b      ; Send all files whose names start with 'a' and end with 'b'.
+  send a?b      ; Ditto, but the name must be exactly three characters long.
+  send a[a-z]b  ; Ditto, but the second character must be a lowercase letter.
+  send a[x\-z]b ; Ditto, except the second character must be 'x', '-', or 'y'.
+  send a[ghi]b  ; Ditto, except the second character must be 'g', 'h', or 'i'.
+  send a[?*]b   ; Ditto, except the second character must be '?' or '*'.
+  send a[\?\*]b ; Same as previous.
+  send *?[a-z]* ; All files with names containing at least one character
+                ; that is followed by a lowercase letter.
+
+   Or, more practically:
+
+  send ck[cuw]*.[cwh]  ; Send the UNIX C-Kermit source files.
+
+   To refer to the C-Kermit sources files and makefile all in one
+   filespec:
+
+  {{makefile,ck[cuw]*.[cwh]}}
+
+   (NOTE: if the entire pattern is a {stringlist}, you must enclose it it
+   TWO pairs of braces, since the SEND command strips the outer brace
+   pair, because of the "enclose in braces if the filename contains
+   spaces" rule).
+
+   If the makefile is called ckuker.mak:
+
+  ck[cuw]*.{[cwh],mak}
+
+   (NOTE: double braces are not needed here since the pattern does not
+   both begin and end with a brace.)
+
+   To add in all the C-Kermit text files:
+
+  ck[cuw]*.{[cwh],mak,txt}
+
+   All of these features can be used anywhere you would type a filename
+   that is allowed to contain wildcards.
+
+   When you are typing at the command prompt, an extra level of quoting
+   is required for the '?' character to defeat its regular function of
+   producing a list of files that match what you have typed so far, for
+   example:
+
+  send ck[cu]?
+
+   lists all the files whose names start with ckc and cku. If you quote
+   the question mark, it is used as a pattern-matching character, for
+   example:
+
+  send ck\?[ft]io.c
+
+   sends all the file and communications i/o modules for all the
+   platforms: ckufio.c, ckutio.c, ckvfio.c, ckvtio.c, etc.
+
+   If, however, a filename actually contains a question mark and you need
+   to refer to it on the command line, you must use three (3)
+   backslashes. For example, if the file is actually called ck?fio.c, you
+   would use:
+
+  send ck\\\?fio.c
+
+   Further notes on quoting:
+
+     * A single backslash is sufficient for quoting a special character
+       at the command prompt or in a command file. However, when passing
+       patterns to macros you'll need double backslashes, and when
+       referring to these patterns within the macro, you'll need to use
+       \fcontents(\%1) (see [498]Section 1.11.5). You should enclose
+       macro argument references in braces in case grouped arguments were
+       passed. Example:
+ define ismatch {
+     if match {\fcont(\%1)} {\fcont(\%2)} {
+         end 0 MATCH
+     } else {
+         end 1 NO MATCH
+     }
+ }
+ ismatch ab*yz a*\\**z           ; Backslash must be doubled
+ ismatch {abc def xyz} *b*e*y*   ; Braces must be used for grouping
+     * Watch out for possible conflicts between {} in filename patterns
+       and {} used for grouping multiple words into a single field, when
+       the pattern has outer braces. For example, in:
+     if match {abc xyz} {a* *z} echo THEY MATCH
+       braces must be used to group "abc xyz" into a single string.
+       Kermit strips off the braces before comparing the string with the
+       pattern. Therefore:
+ if match makefile {makefile,Makefile} echo THEY MATCH
+       does not work, but:
+ if match makefile {{makefile,Makefile}} echo THEY MATCH
+       does.
+     * If you use a pattern that has outer braces, like {*.txt,*.doc}, in
+       a field that accepts a pattern list (like SEND /EXCEPT:xxx),
+       you'll need to add two extra sets of outer braces:
+ send /except:{{{*.txt,*.doc}}} *.*
+
+   C-Kermit's new pattern matching capabilities are also used when
+   C-Kermit is in server mode, so now you can send requests such as:
+
+  get ck[cuw]*.[cwh]
+
+   to a C-Kermit server without having to tell it to SET WILD SHELL
+   first. Previously this would have required:
+
+  mget ckc*.c ckc*.w ckc*.h cku*.c cku*.w cku*.h ckw*.c ckw*.w ckw*.h
+
+   The new pattern matching features make SET WILD SHELL redundant, and
+   barring any objections, it will eventually be phased out. (One
+   possible reason for retaining it would be as an escape mechanism when
+   Kermit does not understand the underlying file system.)
+
+   By the way, patterns such as these are sometimes referred to as
+   "regular expressions", but they are not quite the same. In a true
+   regular expression (for example), "*" means "zero or more repetitions
+   of the previous item", so (for example), "([0-9]*)" would match zero
+   or more digits in parentheses. In Kermit (and in most shells), this
+   matches one digit followed by zero or more characters, within
+   parentheses. Here are some hints:
+
+     * Although you can't match any sequence of digits (or letters, etc),
+       you can match (say) 1, 2, or 3 of them in row. For example, the
+       following pattern matches Kermit backup files (with backup numbers
+       from 1 to 999):
+ *.~{[1-9],[1-9][0-9],[1-9][0-9][0-9]}~
+     * There is presently no NOT operator, so no way to match any
+       character or string EXCEPT the one(s) shown.
+
+   In other wildcarding news...
+
+     * You may now "send xxx" where "xxx" is a directory name, and this
+       will send all the files from the directory xxx, as if you had
+       typed "send xxx/*". You can also use the special shorthand "send
+       ." to send all the files from the current directory.
+     * To easily skip over backup files (the ones whose names end like
+       .~22~) when sending, you can use SEND /NOBACKUP (see [499]Section
+       4.0.6 for details).
+     * When choosing Kermit to expand wildcards, rather than the shell,
+       you can choose whether "dot files" -- files whose names begin with
+       ".", which are normally "invisible" -- should be matched:
+ SET WILD KERMIT /NO-MATCH-DOT-FILES (this is the default)
+ SET WILD KERMIT /MATCH-DOT-FILES    (this allows matching of "." files)
+       or include the /DOTFILES or /NODOTFILES switch on the command you
+       are using, such as SEND or DIRECTORY.
+     * Commands such as DIRECTORY and SEND allow recursive directory
+       traversal. There are also new functions for this to use in
+       scripts. See [500]Section 4.11 for details.
+
+   When building file lists in UNIX, C-Kermit follows symbolic links.
+   Because of this, you might encounter any or all of the following
+   phenomena:
+
+     * Multiple copies of the same file; e.g. one from its real directory
+       and others from links to its real directory, if both the real
+       directory and the links to it are in the wildcard expansion list.
+     * A command might unexpectedly "hang" for a long time because an NFS
+       link might not be responding, or the directory you are looking at
+       contains a link to a huge directory tree (example: "directory
+       /recursive /etc" when /etc/spool is a symlink to /var/spool, which
+       is a large organization's incoming email directory, containing
+       tens of thousands of subdirectories).
+
+   The size of the file list that Kermit can build is limited in most
+   C-Kermit implementations. The limit, if any, depends on the
+   implementation. Use the SHOW FEATURES command and look in the
+   alphabetized options list for MAXWLD to see the value.
+
+    4.9.2. In Kermit 95
+
+   Kermit 95 1.1.19 and later uses the same pattern matching syntax as in
+   UNIX, but (as always) you will encounter numerous difficulties if you
+   use backslash (\) as the directory separator. In any command where K95
+   parses filenames itself (that is, practically any file-oriented
+   command except RUN), you can use forward slash (/) as the directory
+   separator to avoid all the nasty conflicts.
+
+    4.9.3. In VMS, AOS/VS, OS-9, VOS, etc.
+
+   Platforms other than UNIX, Windows 95/98/NT, and OS/2 have their own
+   filename matching capabilities that are, in general, different from
+   Kermit's built-in ones and in any case might conflict with them. For
+   example, [] encloses directory names in VMS.
+
+   Nevertheless you can still use all the pattern-matching capabilities
+   described in [501]Section 4.9.1 by loading a file list into an array
+   (e.g. with \ffiles(*,&a), see [502]Section 4.11.3) and then using IF
+   MATCH on the members.
+     _________________________________________________________________
+
+  4.10. Additional Pathname Controls
+
+   In version 6.0 and earlier, C-Kermit's SET { SEND, RECEIVE } PATHNAMES
+   command had only ON and OFF as options. In version 7.0, there are more
+   choices:
+
+   SET SEND PATHNAMES OFF
+          When sending a file, strip all disk/directory information from
+          the name. Example: "send /usr/olga/letters/oofa.txt" sends the
+          file as "oofa.txt". This applies to actual filenames, not to
+          any as-name you might specify.
+
+   SET SEND PATHNAMES RELATIVE
+          When sending a file, leave the pathname on as given. For
+          example, if your current directory is /usr/olga, "send
+          letters/oofa.txt" sends the file as "letters/oofa.txt", not
+          "/usr/olga/letters/oofa.txt" or "letters.txt".
+
+   SET SEND PATHNAMES ABSOLUTE
+          When sending a file, convert its name to the full, absolute
+          local pathname. For example, if your current directory is
+          /usr/olga, "send letters/oofa.txt" sends the file as
+          "/usr/olga/letters/oofa.txt". NOTE: Even with this setting,
+          device and/or node names are not included. For example, in VMS,
+          any node or device name is stripped; in Windows or OS/2, any
+          disk letter is stripped.
+
+   SET RECEIVE PATHNAMES OFF
+          When receiving a file, strip all disk/directory information
+          from the name before attempting to store it. This applies to
+          incoming filename, not to any as-name you might specify.
+          Example: If a file arrives under the name
+          "/usr/olga/letters/oofa.txt" it is stored simply as "oofa.txt"
+          in your download directory or, if no download directory has
+          been specified, in your current directory.
+
+   SET RECEIVE PATHNAMES RELATIVE
+          When receiving a file, leave the pathname on as it appears in
+          the incoming name, but if the incoming name appears to be
+          absolute, make it relative to your current or download
+          directory. Examples:
+
+          + "oofa.txt" is stored as "oofa.txt".
+          + "letters/oofa.txt" is stored as "letters/oofa.txt"; the
+            "letters" subdirectory is created if it does not already
+            exist.
+          + "/usr/olga/letters/oofa.txt" is stored as
+            "usr/olga/letters/oofa.txt" in your current or download
+            directory, and the "usr", "usr/olga", etc, directories are
+            created if they do not exist.
+
+   SET RECEIVE PATHNAMES ABSOLUTE
+          The incoming filename is used as given. Thus it cannot be
+          stored unless the given path (if any) already exists or can be
+          created. In this case, node, device, or disk designations are
+          NOT stripped, since they most likely were given explicitly by
+          the user as an as-name, meant to be used as given.
+
+   SET RECEIVE PATHNAMES AUTO
+          This is the default, and means RELATIVE if the sender tells me
+          it is a recursive transfer, OFF otherwise.
+
+   Set FILE NAMES CONVERTED now also affects pathnames too. When
+   PATHNAMES are RELATIVE or ABSOLUTE and FILE NAMES are CONVERTED, the
+   file sender converts its native directory-name format to UNIX format,
+   and the file receiver converts from UNIX format to its native one;
+   thus UNIX format is the common intermediate representation for
+   directory hierarchies, as it is in the ZIP/UNZIP programs (which is
+   why ZIP archives are transportable among, UNIX, DOS, and VMS).
+
+   Here's an example in which a file is sent from Windows to UNIX with
+   relative pathnames and FILE NAMES CONVERTED:
+
+  Source name                Intermediate name      Destination Name
+  C:\K95\TMP\OOFA.TXT        K95/TMP/OOFA.TXT       k95/tmp/oofa.txt
+
+   In a more complicated example, we send the same file from Windows to
+   VMS:
+
+  Source name                Intermediate name      Destination Name
+  C:\K95\TMP\OOFA.TXT        K95/TMP/OOFA.TXT       [.K95.TMP]OOFA.TXT
+
+   (Note that disk letters and device designations are always stripped
+   when pathnames are relative).
+
+   As you can imagine, as more and more directory formats are considered,
+   this approach keeps matters simple: on each platform, Kermit must know
+   only its own local format and the common intermediate one. In most
+   cases, the receiver can detect which format is used automatically.
+     _________________________________________________________________
+
+  4.11. Recursive SEND and GET: Transferring Directory Trees
+
+   C-Kermit 7.0 in selected versions (UNIX, VMS, VOS, AOS/VS, Windows,
+   and OS/2 at this writing) now permits the SEND command to traverse
+   directories "recursively" if you ask it to; that is, to send files
+   from the current or specified directory and all of its subdirectories
+   too, and their subdirectories, etc. (Some other commands can do this
+   too, including DIRECTORY.)
+
+   This feature is new to UNIX, Windows, VOS, and OS/2. VMS and AOS/VS
+   have always included "wildcard" or "template" characters that allow
+   this, and in this case, recursive directory traversal could happen
+   behind Kermit's back, i.e. Kermit does not have to do it itself (in
+   VMS, the notation is "[...]" or "[directory...]"; in AOS/VS is "#").
+   In C-Kermit 7.0, however, SEND /RECURSIVE is supported by C-Kermit
+   itself for VMS.
+     _________________________________________________________________
+
+    4.11.1. Command-Line Options
+
+   To descend a directory tree when sending files, use the -L
+   command-line option to indicate that the send operation is to be
+   recursive, and include a name or pattern to be sent. When giving a
+   pattern, you should enclose it in quotes to prevent the shell from
+   expanding it. Examples:
+
+  $ kermit -Ls "/usr/olga/*" # send all of Olga's files in all her directories
+  $ kermit -Ls foo.txt       # send all foo.txt files in this directory tree
+  $ kermit -Ls "*.txt"       # send all .txt files in this directory tree
+  $ kermit -Ls "letters/*"   # send all files in the letters directory tree
+  $ kermit -Ls letters       # send all files in the letters directory tree
+  $ kermit -Ls "*"           # send all files in this directory tree
+  $ kermit -Ls .             # UNIX only: send all files in this directory tree
+  $ kermit -s .              # UNIX only: a filename of . implies -L
+
+   If you let the shell expand wildcards, Kermit only sends files whose
+   names match files in the current or given directory, because the shell
+   replaces an unquoted wildcard expression with the list of matching
+   files -- and the shell does not build recursive lists. Note that the
+   "." notation for the tree rooted at the current directory is allowed
+   only in UNIX, since in Windows and OS/2, it means "*.*"
+   (nonrecursive).
+     _________________________________________________________________
+
+    4.11.2. The SEND /RECURSIVE Command
+
+   If you include the /RECURSIVE switch in a SEND (or MOVE, or similar)
+   command, it means to descend the current or specified directory tree
+   searching for files whose names match the given name or pattern. Since
+   this is not terribly useful unless you also include pathnames with the
+   outbound files, the /RECURSIVE switch also includes an implicit
+   /PATHNAMES:RELATIVE switch (which you can undo by including an
+   explicit /PATHNAMES switch after the /RECURSIVE switch).
+
+   Examples:
+
+   SEND /RECURSIVE *
+          Sends all of the files in the current directory and all the
+          files in all of its subdirectories, and all of their
+          subdirectories, etc, including their relative pathnames. Empty
+          directories are not sent.
+
+   SEND /RECURSIVE /PATHNAMES:ABSOLUTE *
+          Sends all of the files in the current directory and all the
+          files in all of its subdirectories, and all of their
+          subdirectories, etc, including their absolute pathnames.
+
+   SEND /RECURSIVE /PATHNAMES:OFF *
+          Sends all of the files in the current directory and all the
+          files in all of its subdirectories, and all of their
+          subdirectories, etc, without pathnames.
+
+   SEND /RECURSIVE /usr/olga/*
+          Sends all of the files in the /usr/olga directory and all the
+          files in all of its subdirectories, and all of their
+          subdirectories, etc.
+
+   SEND /RECURSIVE /usr/olga (or /usr/olga/)
+          Same as above. If the name is a directory name (with or without
+          a trailing slash), its files are sent, and those of its
+          subdirectories, and their subdirectories, etc (see [503]Section
+          4.9).
+
+   SEND /RECURSIVE /TEXT /usr/olga/*.txt
+          As above, but only files whose names end with ".txt" are sent,
+          and they are sent in text mode (as they would be by default
+          anyway if SET FILE PATTERNS is ON or AUTO).
+
+   SEND .
+          UNIX only: Send all the files in the current directory.
+
+   SEND /RECURSIVE .
+          UNIX only: Sends all of the files in the current directory and
+          all of its subdirectories, etc ([504]Section 4.9).
+
+   The /RECURSIVE switch is different from most other switches in that
+   its effect is immediate (but still local to the command in which it is
+   given), because it determines how filenames are to be parsed. For
+   example, "send *.txt" fails with a parse error ("No files match") if
+   there are no *.txt files in the current directory, but "send
+   /recursive *.txt" succeeds if there are ".txt" files anywhere in the
+   tree rooted at the current directory.
+
+   The /RECURSIVE switch also affects the file lists displayed if you
+   type "?" in a filename field. "send ./?" lists the regular files in
+   the current directory, but "send /recursive ./?" lists the entire
+   directory tree rooted at the current directory.
+     _________________________________________________________________
+
+    4.11.3. The GET /RECURSIVE Command
+
+   In a client/server setting, the client can also request a recursive
+   transfer with:
+
+   GET /RECURSIVE [ other switches ] remote-filespec [ local-spec ]
+
+   In which remote file specification can be a directory name, a
+   filename, a wildcard, or any combination. If the local-spec is not
+   given (and PATHNAMES are RELATIVE), incoming files and directories go
+   into the current local directory. If local-spec is given and is a
+   directory, it becomes the root of the tree into which the incoming
+   files and directories are placed. If local-spec has the syntax of a
+   directory name (e.g. in UNIX it ends with /), C-Kermit creates the
+   directory and then places the incoming files into it. If local-spec is
+   a filename (not recommended), then all incoming files are stored with
+   that name with collisions handled according to the FILE COLLISION
+   setting.
+
+   Again, the normal method for transferring directory trees uses
+   relative pathnames, and this is the default when the sender has been
+   given the /RECURSIVE switch. The action at the receiver depends on its
+   RECEIVE PATHNAMES setting. The default is AUTO, meaning that if the
+   sender tells it to expect a recursive transfer, then it should
+   automatically switch to relative pathnames for this transfer only;
+   otherwise it obeys the RECEIVE PATHNAMES setting of OFF, ABSOLUTE, or
+   RELATIVE.
+
+   What happens if a file arrives that has an absolute pathname, when the
+   receiver has been told to use only relative pathnames? As a security
+   precaution, in this case the receiver treats the name as if it was
+   relative. For example, if a file arrives as:
+
+  /usr/olga/oofa.txt
+
+   The receiver creates a "usr" subdirectory in its current directory,
+   and then an "olga" subdirectory under the "usr" subdirectory in which
+   to store the incoming file.
+
+   Suppose, however there is a sequence of directories:
+
+  /usr/olga/a/b/c/d/
+
+   in which "a" contains nothing but a subdirectory "b", which in turn
+   contains nothing but a subdirectory "c", which in turn contains
+   nothing but a subdirectory "d", which contains nothing at all. Thus
+   there are no files in the "/usr/olga/a/" tree, and so it is not sent,
+   and therefore it is not reproduced on the target computer.
+     _________________________________________________________________
+
+    4.11.4. New and Changed File Functions
+
+   C-Kermit 7.0 adds the following functions:
+
+   \ffiles(pattern[,&a])
+          This function has been changed to match only regular files in
+          the current or given directory, and to take an optional array
+          name as a second argument (explained below).
+
+   \fdirectories(pattern[,&a])
+          Returns the number of directories that match the given pattern.
+          If the pattern does not include a directory, then the search is
+          performed in the current directory.
+
+   \frfiles(pattern[,&a])
+          Returns the number of files in the current or given directory
+          and all of its subdirectories, and their subdirectories, etc,
+          that match the given pattern. Warning -- this one can take
+          quite some time if performed at the root of a large directory
+          tree.
+
+   \frdirectories(pattern[,&a])
+          Returns the number of directories in the current or given
+          directory and all of its subdirectories, and their
+          subdirectories, etc, that match the given pattern.
+
+   Each of these functions builds up a list of files to be returned by
+   the \fnextfile() function, just as \ffiles() always has done. (This
+   can also be done with the /ARRAY switch of the DIRECTORY command; see
+   [505]Sections 4.5.1 and [506]7.10).
+
+   Each of these functions can be given an array name as an optional
+   second argument. If an array name is supplied, the array will contain
+   the number of files as its 0th element, and the filenames in elements
+   1 through last. If the array already existed, its previous contents
+   are lost. For example, if the current directory contains two files,
+   oofa.txt and foo.bar, then "\ffiles(*,&a)" creates an array \&a[] with
+   a dimension of 2, containing the following elements:
+
+ \&a[0] = 2
+ \&a[1] = oofa.txt
+ \&a[2] = foo.bar
+
+   If no files match the specification given in the first argument, the
+   array gets a dimension of 0, which is the same as undeclaring the
+   array.
+
+   Note that the order in which the array is filled (and in which
+   \fnextfile() returns filenames) is indeterminate (but see [507]Section
+   7.10.5).
+
+   Here's an example that builds and prints a list of all the file whose
+   names end in .txt in the current directory and all its descendents:
+
+  asg \%n \frfiles(*.txt)
+  declare \&a[\%n]
+  for \%i 1 \%n 1 {
+      asg \&a[\%i] \fnextfile()
+      echo \flpad(\%i,4). "\&a[\%i]"
+  }
+
+   Alternatively, using the array method, and then printing the filenames
+   in alphabetic order (see [508]Section 7.10.3 and [509]7.10.5):
+
+  asg \%n \frfiles(*.txt,&a)
+  sort &a
+  for \%i 1 \%n 1 {
+      echo \flpad(\%i,4). "\&a[\%i]"
+  }
+
+   Or even more simply:
+
+  asg \%n \frfiles(*.txt,&a)
+  sort &a
+  show array &a
+
+   As noted elsewhere, the file lists built by \ffiles(), \frfiles(),
+   etc, are now "safe" in the sense that SEND and other file-related
+   commands can reference \fnextfile() without resetting the list:
+
+  set send pathnames relative
+  for \%i 1 \frfiles(*.txt) 1 {
+      asg \%a \fnextfile()
+      echo Sending \%a...
+      send \%a
+      if fail break
+  }
+
+   Copying to an array (as shown on p.398 of [510]Using C-Kermit 2nd Ed)
+   is no longer necessary.
+     _________________________________________________________________
+
+    4.11.5. Moving Directory Trees Between Like Systems
+
+    4.11.5.1. UNIX to UNIX
+
+   Transferring a directory tree from one computer to another replicates
+   the file sender's arrangement of files and directories on the file
+   receiver's computer. Normally this is done using relative pathnames,
+   since the user IDs might not be identical on the two computers. Let's
+   say both computers are UNIX based, running C-Kermit 7.0 or later. On
+   the sending computer (leaving out the connection details, etc):
+
+  C-Kermit> cd /usr/olga
+  C-Kermit> send /recursive .
+
+   The /RECURSIVE switch tells C-Kermit to descend through the directory
+   tree and to include relative pathnames on outbound filenames.
+
+   On the receiving computer:
+
+  C-Kermit> mkdir olgas-files           ; Make a new directory.
+  C-Kermit> cd olgas-files              ; CD to it.
+  C-Kermit> receive /recursive          ; = /PATHNAMES:RELATIVE
+
+   Each Kermit program recognizes that the other is running under UNIX
+   and switches to binary mode and literal filenames automatically.
+   Directories are automatically created on the receiving system as
+   needed. File dates and permissions are automatically reproduced from
+   source to destination.
+
+    4.11.5.2. VMS to VMS
+
+   To send recursively from VMS, simply include the /RECURSIVE switch,
+   for example at the sender:
+
+  $ kermit
+  C-Kermit> cd [olga]
+  C-Kermit> send /recursive *.*;0
+
+   And at the receiver:
+
+  C-Kermit> cd [.olga]
+  C-Kermit> receive /recursive
+
+   The notation "..." within directory brackets in VMS means "this
+   directory and all directories below it"; the /RECURSIVE switch, when
+   given to the sender, implies the use of "..." in the file
+   specification so you don't have to include "..."; but it makes no
+   difference if you do:
+
+  $ kermit
+  C-Kermit> send /recursive [olga...]*.*;0
+
+   And at the receiver:
+
+  C-Kermit> cd [.olga]
+  C-Kermit> receive /recursive
+
+   In either case, since both systems recognize each other as VMS, they
+   switch into LABELED transfer mode automatically.
+     _________________________________________________________________
+
+    4.11.6. Moving Directory Trees Between Unlike Systems
+
+   There are several difficulties with recursive transfers between unlike
+   systems:
+
+     * File formats can be different, especially text files character
+       sets and record formats. This can now be handled by using SET FILE
+       PATTERN, SET FILE TEXT-PATTERNS, and SET FILE BINARY-PATTERNS
+       ([511]Section 4.3).
+     * File naming conventions are different. For example, one system
+       might allow (and use) longer filenames than the other. You can
+       tell Kermit how to handle file names with the normal "set file
+       names" and "set file collision" mechanisms. Most modern Kermits
+       are fairly tolerant of illegal filenames and should not fail
+       simply because of an incoming filename; rather, it will do its
+       best to convert it to a recognizable and unique legal filename.
+     * Directory notations can be different, e.g. backslashes instead of
+       slashes, brackets, parentheses, spaces, etc. But this is now
+       handled by converting pathnames to a standard format during
+       transfer ([512]Section 4.10).
+
+   So now, for the first time, it is possible to send directory trees
+   among any combination of UNIX, DOS, Windows, OS/2, VMS, AOS/VS, etc.
+   Here's an example sending files from an HP-UX system (where text files
+   are encoded in the HP Roman8 character set) to a PC with K95 (where
+   text files are encoded in CP850):
+
+ Sender:
+  cd xxx                           ; CD to root of source tree
+  set file type binary             ; Default transfer mode
+  set file character-set hp-roman8 ; Local character set for text files
+  set xfer character-set latin1    ; Transfer character set
+  set file patterns on             ; Enable automatic file-type switching...
+  set file binary-patterns *.Z *.gz *.o  ; based on these patterns...
+  set file text-patterns *.txt *.c *.h   ; for binary and text files.
+  send /recursive *                ; Send all the file in this directory tree
+
+ Receiver:
+  cd yyy                           ; CD to root of destination tree
+  set file character-set cp850     ; Local character set for text files
+  receive /pathnames:relative      ; Receive with pathnames
+
+   Notes:
+     * Replace "xxx" and "yyy" with the desired directories.
+     * Replace the file character sets appropriately.
+     * Change the patterns as needed (or just use the built-in default
+       lists).
+     * SEND /RECURSIVE also implies /PATHNAMES:RELATIVE.
+     * The file sender tells the file receiver the transfer mode of each
+       file.
+     * The file sender tells the file receiver the transfer character
+       set.
+     * By default, destination file dates will be the same as on the
+       source.
+     * Many of the settings shown might already be set by default.
+     * See [513]Sections 4.3, [514]4.10, and [515]4.15 for additional
+       explanation.
+
+   If you are refreshing an existing directory on the destination
+   computer, use "set file collision update" or other appropriate file
+   collision option to handle filename collisions.
+     _________________________________________________________________
+
+  4.12. Where Did My File Go?
+
+   Now that Kermit can be started by clicking on desktop icons (thus
+   obscuring the concept of "current directory"), and can have a download
+   directory, and can create directories for incoming files on the fly,
+   etc, sometimes it is easy to lose a file after transfer. Of course, if
+   you keep a transaction log:
+
+  LOG TRANSACTIONS
+
+   it will record the fate and final resting place of each file. But in
+   case you did not keep a log, the new command:
+
+  WHERE
+
+   added in C-Kermit 7.0, gives you as much information as it has about
+   the location of the last files transferred, including the pathname
+   reported by the receiving Kermit, if any, when C-Kermit is the sender.
+   This information was also added to SHOW FILE in somewhat less detail.
+     _________________________________________________________________
+
+  4.13. File Output Buffer Control
+
+   (UNIX only). The new command SET FILE OUTPUT lets you control how
+   incoming files are written to disk:
+
+   SET FILE OUTPUT BUFFERED [ size ]
+          Chooses buffered file output; this is the default. UNIX does
+          its normal sort of disk buffering. The optional size specifies
+          Kermit's own file output buffer size, and therefore the
+          frequency of disk accesses (write() system calls) -- the bigger
+          the size, the fewer the disk accesses.
+
+   SET FILE OUTPUT UNBUFFERED [ size ]
+          This forces each file output write() call to actually commit
+          the data to disk immediately. Choosing this option will usually
+          slow file reception down.
+
+   SET FILE OUTPUT BLOCKING
+          Write() calls should not return until they are complete. This
+          is the normal setting, and it lets Kermit detect disk-write
+          errors immediately.
+
+   SET FILE OUTPUT NONBLOCKING
+          Write() calls should return immediately. This can speed up file
+          reception, but also delay the detection of disk-write errors.
+
+   Experimentation with these parameters should be harmless, and might
+   (or might not) have a perceptible, even dramatic, effect on
+   performance.
+     _________________________________________________________________
+
+  4.14. Improved Responsiveness
+
+   In version 7.0, C-Kermit's file-transfer protocol engine has been
+   tuned for additional speed and responsiveness.
+
+     * Binary-mode transfers over 8-bit connections, a very common case,
+       are now handled in a special way that minimizes overhead.
+     * SET TRANSFER CRC-CALCULATION is now OFF by default, rather than
+       ON. (This affects only the overall per-transfer CRC, \v(crc16),
+       not the per-packet CRCs)
+     * Connection loss during file transfer is now detected immediately
+       in most cases on Internet connections and on serial connections
+       when CARRIER-WATCH is not set to OFF.
+     _________________________________________________________________
+
+  4.15. Doubling and Ignoring Characters for Transparency
+
+   The following commands were added in 7.0, primarily to allow
+   successful file transfer through ARPAnet TACs and with Honeywell DPS6
+   systems, but can be used in any setting where they might be needed:
+
+   SET SEND DOUBLE-CHAR { [ char [ char [ ... ] ] ], NONE }
+          Tells C-Kermit to double the specified characters (use decimal
+          notation) in packets that it sends. For example, if you are
+          sending files through a device that uses @ as an escape
+          character, but allows you to send a single copy of @ through by
+          doubling it, use "set send double 64".
+
+   SET RECEIVE IGNORE-CHAR [ char [ char [ ... ] ] ]
+          Tells C-Kermit to ignore the specified character(s) in incoming
+          packets. Use this, for example, when something between the
+          sender and receiver is inserting linefeeds for wrapping, NULs
+          for padding, etc.
+     _________________________________________________________________
+
+  4.16. New File-Transfer Display Formats
+
+   SET TRANSFER DISPLAY { BRIEF, CRT, FULLSCREEN, NONE, SERIAL }
+          Selects the file-transfer display format.
+
+   BRIEF is the new one. This writes one line to the screen per file,
+   showing the file's name, transfer mode, size, the status of the
+   transfer, and when the transfer is successful, the effective data rate
+   in characters per second (CPS). Example:
+
+  SEND ckcfn3.o (binary) (59216 bytes): OK (0.104 sec, 570206 cps)
+  SEND ckcfns.o (binary) (114436 bytes): OK (0.148 sec, 772006 cps)
+  SEND ckcmai.c (text) (79147 bytes): OK (0.180 sec, 438543 cps)
+  SEND ckcmai.o (binary) (35396 bytes): OK (0.060 sec, 587494 cps)
+  SEND ckcnet.o (binary) (62772 bytes): REFUSED
+  SEND ckcpro.o (binary) (121448 bytes): OK (0.173 sec, 703928 cps)
+  SEND ckcpro.w (text) (63687 bytes): OK (0.141 sec, 453059 cps)
+  SEND makefile (text) (186636 bytes): OK (0.444 sec, 420471 cps)
+  SEND wermit (binary) (1064960 bytes): OK (2.207 sec, 482477 cps)
+
+   Note that transfer times are now obtained in fractional seconds,
+   rather than whole seconds, so the CPS figures are more accurate (the
+   display shows 3 decimal places, but internally the figure is generally
+   precise to the microsecond).
+     _________________________________________________________________
+
+  4.17. New Transaction Log Formats
+
+   The new command:
+
+  SET TRANSACTION-LOG { VERBOSE, FTP, BRIEF [ separator ] }
+
+   lets you choose the format of the transaction log. VERBOSE (the
+   default) indicates the traditional format described in the book. BRIEF
+   and FTP are new. This command must be given prior to the LOG
+   TRANSACTION command if a non-VERBOSE type is desired.
+
+    4.17.1. The BRIEF Format
+
+   BRIEF chooses a one-line per file format suitable for direct
+   importation into databases like Informix, Oracle, or Sybase, in which:
+
+     * Each record has 8 fields.
+     * Fields are separated by a non-alphanumeric separator character.
+     * The default separator character is comma (,).
+     * Any field containing the separator character is enclosed in
+       doublequotes.
+     * The final field is enclosed in doublequotes.
+
+   The fields are:
+
+    1. Date in yyyymmdd format
+    2. Time in hh:mm:ss format
+    3. Action: SEND or RECV
+    4. The local filename
+    5. The size of the file
+    6. The transfer mode (text, binary, image, labeled)
+    7. The status of the transfer: OK or FAILED
+    8. Additional status-dependent info, in doublequotes.
+
+   Examples:
+
+  20000208,12:08:52,RECV,/u/olga/oofa.txt,5246,text,OK,"0.284sec 18443cps"
+  20000208,12:09:31,SEND,/u/olga/oofa.exe,32768,binary,OK,"1.243sec 26362cps"
+  20000208,12:10:02,SEND,"/u/olga/a,b",10130,text,FAILED,"Refused: date"
+
+   Note how the filename is enclosed in doublequotes in the final
+   example, because it contains a comma.
+
+   To obtain BRIEF format, you must give the SET TRANSACTION-LOG BRIEF
+   command before the LOG TRANSACTIONS command. (If you give them in the
+   opposite order, a heading is written to the log by the LOG command.)
+     _________________________________________________________________
+
+    4.17.2. The FTP Format
+
+   SET TRANSACTION-LOG FTP (available only in UNIX) chooses a format that
+   is compatible with the WU-FTPD (Washington University FTP daemon) log,
+   and so can be processed by any software that processes the WU-FTPD
+   log. It logs only transfers in and out, both successful and failed
+   (but success or failure is not indicated, due to lack of a field in
+   the WU-FTPD log format for this purpose). Non-transfer events are not
+   recorded.
+
+   Unlike other logs, the FTP-format transaction log is opened in append
+   mode by default. This allows you to easily keep a record of all your
+   kermit transfers, and it also allows the same log to be shared by
+   multiple simultaneous Kermit processes or (permissions permitting)
+   users. You can, of course, force creation of a new logfile by
+   specifying the NEW keyword after the filename, e.g.
+
+  log transactions oofa.log new
+
+   All records in the FTP-style log are in a consistent format. The first
+   field is fixed-length and contains spaces; subsequent fields are
+   variable length, contain no spaces, and are separated by one or more
+   spaces. The fields are:
+
+   Timestamp
+          This is an asctime-style timestamp, example: "Wed Sep 16
+          20:19:05 1999" It is always exactly 24 characters long, and the
+          subfields are always in fixed positions.
+
+   Elapsed time
+          The whole number of seconds required to transfer the file, as a
+          string of decimal digits, e.g. "24".
+
+   Connection
+          The name of the network host to which C-Kermit is connected, or
+          the name of the serial device through which it has dialed (or
+          has a direct connection), or "/dev/tty" for transfers in remote
+          mode.
+
+   Bytes transferred
+          The number of bytes transferred, decimal digits, e.g.
+          "1537904".
+
+   Filename
+          The name of the file that was transferred, e.g.
+          "/pub/ftp/kermit/a/README.TXT". If the filename contains any
+          spaces or control characters, each such character is replaced
+          by an underscore ('_') character.
+
+   Mode
+          The letter 'b' if the file was transferred in binary mode, or
+          'a' if it was transferred in text (ASCII) mode.
+
+   Options
+          This field always contains an underscore ('_') character.
+
+   Direction
+          The letter 'o' if the file was transferred Out, and 'i' if the
+          file was transferred In.
+
+   User class
+          The letter 'r' indicates the file was transferred by a Real
+          user.
+
+   User identification
+          The ID of the user who transferred the file.
+
+   Server identification
+          The string "kermit". This distinguishes a Kermit transfer log
+          record from a WU-FTPD record, which contains "ftp" in this
+          field.
+
+   Authentication class
+          The digit '1' if we know the user's ID on the client system,
+          otherwise '0'. Currently, always '0'.
+
+   Authenticated user
+          If the authentication class is '1', this is the user's ID on
+          the client system. Otherwise it is an asterisk ('*'). Currently
+          it is always an asterisk.
+
+   Examples:
+
+  Thu Oct 22 17:42:48 1998 0 * 94 /usr/olga/new.x a _ i r olga kermit 0 *
+  Thu Oct 22 17:51:29 1998 1 * 147899 /usr/olga/test.c a _ o r olga kermit 0 *
+  Thu Oct 22 17:51:44 1998 1 * 235 /usr/olga/test.o b _ i r olga kermit 0 *
+  Fri Oct 23 12:10:25 1998 0 * 235 /usr/olga/x.ksc a _ o r olga kermit 0 *
+
+   Note that an ftp-format transaction log can also be selected on the
+   Kermit command line as follows:
+
+  kermit --xferfile:filespec
+
+   This is equivalent to:
+
+  SET TRANSACTION-LOG FTP
+  LOG TRANSACTIONS filespec APPEND
+
+   Conceivably it could be possible to have a system-wide shared Kermit
+   log, except that UNIX lacks any notion of an append-only file; thus
+   any user who could append to the log could also delete it (or alter
+   it). This problem could be worked around using setuid/setgid tricks,
+   but these would most likely interfere with the other setuid/setgid
+   tricks C-Kermit must use for getting at dialout devices and UUCP
+   logfiles.
+     _________________________________________________________________
+
+  4.18. Unprefixing NUL
+
+   As of 6.1.193 Alpha.10, C-Kermit can finally send and receive
+   file-transfer packets in which NUL (ASCII 0) is unprefixed (no more
+   NUL-terminated packets!). NUL is, of course, extremely prevalent in
+   binary files such as executables, and this has been a significant
+   source of packet overhead. For example, when transferring itself (the
+   SunOS C-Kermit executable) with minimal prefixing and 9000-byte
+   packets, we see:
+
+  File size:                       1064960
+  Packet chars with 0 prefixed:    1199629  overhead = 12.65%
+  Packet chars with 0 unprefixed:  1062393  overhead = -0.03%
+
+   Transfer rates go up accordingly, not only because of the reduced
+   amount of i/o, but also because less computation is required on each
+   end.
+     _________________________________________________________________
+
+  4.19. Clear-Channel Protocol
+
+   Now that C-Kermit itself is capable of sending and receiving any byte
+   at all on a clear channel ([516]Section 4.18), it is, for the first
+   time, in a position to negotiate a clear channel with the other
+   Kermit, giving it permission (but not requiring it) to unprefix any
+   and all characters that it knows are safe. In general this means all
+   but the Kermit start-of-packet character (normally Ctrl-A), Carriage
+   Return (not only Kermit's end-of-packet character, but also treated
+   specially on Telnet NVT links), and IAC (255, also special to Telnet).
+
+   By default, C-Kermit will say it has a clear channel only if it has
+   opened a TCP socket. Since the Kermit program on the far end of a
+   TCP/IP connection generally does not know it has a TCP/IP connection,
+   it will not announce a clear channel unless it has been told to do so.
+   The command is:
+
+   SET CLEAR-CHANNEL { ON, OFF, AUTO }
+
+   AUTO is the default, meaning that the clear-channel status is
+   determined automatically from the type of connection. ON means to
+   announce a clear channel, OFF means not to announce it. Use SHOW
+   STREAMING ([517]Section 4.20) to see the current CLEAR-CHANNEL status.
+   Synonym: SET CLEARCHANNEL.
+
+   CLEAR-CHANNEL is also set if you start C-Kermit with the -I switch
+   (see [518]Section 4.20).
+
+   Whenever a clear channel is negotiated, the resulting
+   control-character unprefixing is "sticky"; that is, it remains in
+   effect after the transfer so you can use SHOW CONTROL to see what was
+   negotiated.
+
+   You can also see whether a clear channel was negotiated in the
+   STATISTICS /VERBOSE Display.
+
+   The advantage of the clear channel feature is that it can make file
+   transfers go faster automatically. The disadvantage would be
+   file-transfer failures if the channel is not truly clear, for example
+   if C-Kermit made a Telnet connection to a terminal server, and then
+   dialed out from there; or if C-Kermit made an Rlogin connection to
+   host and then made a Telnet connection from there to another host. If
+   a file transfer fails on a TCP/IP connection, use SHOW CONTROL to
+   check whether control characters became unprefixed as a result of
+   protocol negotiations, and/or SHOW STREAMING ([519]Section 4.20) to
+   see if "clear-channel" was negotiated. If this happened, use SET
+   CLEAR-CHANNEL OFF and SET PREFIXING CAUTIOUS (or whatever) to prevent
+   it from happening again.
+     _________________________________________________________________
+
+  4.20. Streaming Protocol
+
+   A new Kermit protocol option called "streaming" was added in C-Kermit
+   7.0. The idea is that if the two Kermit partners have a reliable
+   transport (such as TCP/IP or X.25) between them, then there is no need
+   to send ACKs for Data packets, or NAKs, since a reliable transport
+   will, by definition, deliver all packets in order and undamaged. On
+   such a connection, streaming cuts down not only on Kermit program
+   overhead (switching back and forth between reading and sending
+   packets), but also tends to make the underlying transport use itself
+   more efficiently (e.g. by defeating the Nagle algorithm and/or Delayed
+   ACK stratagem of the TCP layer). Furthermore, it allows transfers to
+   work smoothly on extremely slow network congestions that would
+   otherwise cause timeouts and retransmissions, and even failure when
+   the retry limit was exceeded.
+
+   The trick is knowing when we can stream:
+
+    1. If C-Kermit has opened a TCP socket or X.25 connection, it offers
+       stream.
+    2. If C-Kermit has been started with the -I (uppercase) option, or if
+       it has been told to SET RELIABLE ON, it offers to stream.
+    3. If C-Kermit is in remote mode, and has been told to SET RELIABLE
+       AUTO (or ON), it always offers to stream, and also always agrees
+       to stream, if the other Kermit offers. Unless you take explicit
+       actions to override the defaults, this allows the local Kermit
+       (the one that made the connection, and so knows whether it's
+       reliable) to control streaming.
+
+   (Note that an offer to stream also results in a Clear-Channel
+   announcement if CLEAR-CHANNEL is set to AUTO; see [520]Section 4.19.)
+
+   When BOTH Kermits offer to stream, then they stream; otherwise they
+   don't. Thus streaming-capable Kermit programs interoperate
+   automatically and transparently with nonstreaming ones. If the two
+   Kermits do agree to stream, you'll see the word "STREAMING" on the
+   fullscreen file-transfer display in the Window Slots field. You can
+   also find out afterwards with the STATISTICS or SHOW STREAMING
+   commands.
+
+     WARNING: Automatic choice of streaming is based on the assumption
+     of a "direct" end-to-end network connection; for example, a Telnet
+     or Rlogin connection from host A to host B, and transferring files
+     between A and B. However, if your connection has additional
+     components -- something "in the middle" (B) that you have made a
+     network connection to, which makes a separate connection to the
+     destination host (C), then you don't really have a reliable
+     connection, but C-Kermit has no way of knowing this; transferring
+     files between A and C will probably fail. In such cases, you'll
+     need to tell the *local* C-Kermit to "set reliable off" before
+     transferring files (it does no good to give this command to the
+     remote Kermit since the local one controls the RELIABLE setting).
+
+   Streaming is like using an infinite window size, with no timeouts and
+   no tolerance for transmission errors (since there shouldn't be any).
+   It relies on the underlying transport for flow control, error
+   correction, timeouts, and retransmission. Thus it is very suitable for
+   use on TCP/IP connections, especially slow or bursty ones, since
+   Kermit's packet timeouts won't interfere with the transfer -- each
+   packet takes as long to reach its destination as it takes TCP to
+   deliver it. If TCP can't deliver the packet within its own timeout
+   period (over which Kermit has no control), it signals a fatal error.
+   Just like FTP.
+
+   Streaming goes much faster than non-streaming when a relatively small
+   packet length is used, and it tends to go faster than non-streaming
+   with even the longest packet lengths. The Kermit window size is
+   irrelevant to streaming protocol, but still might affect performance
+   in small ways since it can result in different paths through the code.
+
+   The definition of "reliable transport" does not necessarily demand
+   8-bit and control-character transparency. Streaming can work with
+   parity and/or control-character prefixing just as well (but not as
+   fast) as without them; in such cases you can leave RELIABLE set to ON,
+   but set CLEARCHANNEL and/or PARITY appropriately.
+
+   Maximum performance -- comparable to and often exceeding FTP -- is
+   achieved on socket-to-socket connections (in which the considerable
+   overhead of the terminal driver and Telnet or Rlogin server is
+   eliminated) with long packets and the new "brief" file-transfer
+   display ([521]Section 4.16).
+     _________________________________________________________________
+
+    4.20.1. Commands for Streaming
+
+   SET RELIABLE { ON, OFF, AUTO }
+          SET RELIABLE ON tells Kermit that it has a reliable transport.
+          SET RELIABLE OFF tells Kermit the transport is not reliable.
+          SET RELIABLE AUTO tells Kermit that it should SET RELIABLE ON
+          whenever it makes a reliable connection (e.g. TELNET or SET
+          HOST on a TCP/IP or X.25 network), and when in remote mode it
+          should believe the transport is reliable if the other Kermit
+          says it is during Kermit protocol negotiation.
+
+   AUTO is the default; the Kermit program that makes the connection
+   knows whether it is reliable, and tells the remote Kermit.
+
+   The RELIABLE setting has several effects, including:
+
+     * It can affect the timeouts used during normal ACK/NAK protocol.
+     * It can affect the clear-channel announcement.
+     * It can affect streaming.
+
+   If you TELNET or SET HOST somewhere, this includes an implicit SET
+   RELIABLE ON command. The -I command-line option is equivalent to SET
+   RELIABLE ON.
+
+   Since SET RELIABLE ON (and -I) also implies SET CLEAR CHANNEL ON, you
+   might find that in certain cases you need to tell Kermit that even
+   though the connection is reliable, it doesn't have a clear channel
+   after all:
+
+  SET CLEAR-CHANNEL OFF
+  SET PREFIXING CAUTIOUS ; or whatever...
+
+   You can control streaming without affecting the other items with:
+
+  SET STREAMING { ON, OFF, AUTO }
+
+   AUTO is the default, meaning streaming will occur if Kermit has made a
+   TCP/IP connection or if RELIABLE is ON (or it was started with the -I
+   command line option). OFF means don't stream; ON means offer to stream
+   no matter what.
+     _________________________________________________________________
+
+    4.20.2. Examples of Streaming
+
+   Here we look at the use and behavior of streaming on several different
+   kinds of connections, and compare its performance with non-streaming
+   transfers.
+
+    4.20.2.1. Streaming on Socket-to-Socket Connections
+
+   Here we get streaming automatically when both Kermit programs are
+   capable of it, since they both make socket connections. For example,
+   on the far end:
+
+  C-Kermit> set host * 3000
+  C-Kermit> server
+
+   and on the near end:
+
+  C-Kermit> set host foo.bar.xyz.com 3000
+  (now give SEND and GET command)
+
+   All subsequent file transfers use streaming automatically.
+
+   Here are the results from 84 trials, run on a production network,
+   disk-to-disk, in which a 1-MB binary file (the SunOS C-Kermit Sparc
+   executable) was sent from a Sun Sparc-10 with SunOS 4.1.3 to an IBM
+   Power Server 850 with AIX 4.1, socket-to-socket, over a 10Mbps 10BaseT
+   Ethernet, using minimal control-character unprefixing, window sizes
+   from 10 to 32, and packet sizes from 1450 to 9010:
+
+                Streaming    Nonstreaming
+  Max CPS         748955        683354
+  Min CPS         221522        172491
+  Mean CPS        646134        558680
+  Median CPS      678043        595874
+  Std Dev         101424        111493
+
+   Correlations:
+
+  CPS and window size:   -0.036
+  CPS and packet length:  0.254
+  CPS and streaming:      0.382
+
+   Note that the relationship between streaming and throughput is
+   significantly stronger than that between CPS and window size or packet
+   length.
+
+   Also note that this and all other performance measurements in this
+   section are snapshots in time; the results could be much different at
+   other times when the load on the systems and/or the network is higher
+   or lower.
+
+   In a similar socket-to-socket trial, but this time over a wide-area
+   TCP/IP connection (from New York City to Logan, Utah, about 2000
+   miles), the following results were obtained:
+
+                Streaming    Nonstreaming
+  Max CPS         338226        318203
+  Min CPS         191659        132314
+  Mean CPS        293744        259240
+  Median CPS      300845        273271
+  Std Dev          41914         52351
+
+   Correlations:
+
+  CPS and window size:    0.164
+  CPS and packet length:  0.123
+  CPS and streaming:      0.346
+     _________________________________________________________________
+
+    4.20.2.2. Streaming on Telnet Connections
+
+   In this case the local copy of Kermit is told to TELNET or SET HOST,
+   and so it knows it has a reliable connection and -- unless it has been
+   told not to -- will offer to stream, and the other Kermit program,
+   since it has STREAMING set to AUTO, agrees.
+
+   Since we have a reliable connection, we'll also get control-character
+   unprefixing automatically because of the new clear-channel protocol
+   ([522]Section 4.19).
+
+   Any errors that occur during streaming are fatal to the transfer. The
+   message is "Transmission error on reliable link". Should this happen:
+
+    1. Check the remote Kermit's flow control setting (SHOW
+       COMMUNICATIONS). If it is NONE, change it to XON/XOFF, or vice
+       versa. If it is XON/XOFF (or you just changed it to XOFF/XOFF),
+       make sure the file sender is prefixing the XON and XOFF
+       characters. In the most drastic case, use "set prefix all" to
+       force prefixing of all control characters.
+    2. The remote Telnet server might chop off the 8th bit. In that case,
+       tell C-Kermit to "set parity space". Or, you might be able to
+       force the Telnet to allow eight-bit data by telling C-Kermit to
+       "set telopt binary request accept" -- that is, request the Telnet
+       server to enter binary mode, and accept binary-mode bids from the
+       server.
+    3. The remote Telnet server might have a buffering limitation. If a
+       and b don't cure the problem, tell the file receiver to "set
+       receive packet-length 1000" (or other number -- use the largest
+       one that works). This too, is no different from the non-streaming
+       case (more about this in [523]Section 4.20.2.3).
+
+   And remember you can continue interrupted binary-mode transfers where
+   they left off with the RESEND (= SEND /RECOVER) command.
+
+   Here are the figures for the same 84 trials between the same Sun and
+   IBM hosts as in 4.20.2.1, on the same network, but over a Telnet
+   connection rather than socket-to-socket:
+
+                  Streaming    Nonstreaming
+  Max CPS         350088        322523
+  Min CPS          95547        173152
+  Mean CPS        321372        281830
+  Median CPS      342604        291469
+  Std Dev          40503         29948
+
+   Correlations:
+
+  CPS and window size:    0.001
+  CPS and packet length:  0.152
+  CPS and streaming:      0.128
+
+   Here the effect is not as emphatic as in the socket-to-socket case,
+   yet on the whole streaming tends to be beneficial.
+
+   Additional measurements on HP-UX using C-Kermit 7.0 Beta.06:
+
+                  Windowing     Streaming
+  HP-UX 8->8      not tested       14Kcps
+  HP-UX 8->9      not tested       76Kcps
+  HP-UX 8->10      36Kcps          66Kcps
+  HP-UX 9->9      not tested      190Kcps
+  HP-UX 9->10     160Kcps         378Kcps
+     _________________________________________________________________
+
+    4.20.2.3. Streaming with Limited Packet Length
+
+   The IRIX telnet server (at least the ones observed in IRIX 5.3 and
+   6.2) does not allow Kermit to send packets longer than 4096 bytes.
+   Thus when sending from IRIX C-Kermit when it is on the remote end of a
+   Telnet connection, the packet length must be 4K or less. Trials in
+   this case (in which packet lengths range from 1450 to 4000) show a
+   strong advantage for streaming, which would be evident in any other
+   case where the packet length is restricted, and stronger the shorter
+   the maximum packet length.
+
+                  Streaming    Nonstreaming
+  Max CPS         426187        366870
+  Min CPS         407500        276517
+  Mean CPS        415226        339168
+  Median CPS      414139        343803
+  Std Dev           6094         25851
+
+   Correlations:
+
+  CPS and window size:    0.116
+  CPS and packet length:  0.241
+  CPS and streaming:      0.901
+     _________________________________________________________________
+
+    4.20.2.4. Streaming on Dialup Connections
+
+   Here "dialup" refers to a "direct" dialup connection, not a SLIP or
+   PPP connection, which is only a particular kind of TCP/IP connection.
+
+   Attempt this at your own risk, and then only if (a) you have
+   error-correcting modems, and (b) the connections between the modems
+   and computers are also error-free, perfectly flow-controlled, and free
+   of interrupt conflicts. Streaming can be used effectively and to
+   fairly good advantage on such connections, but remember that the
+   transfer is fatal if even one error is detected (also remember that
+   should a binary-mode transfer fail, it can be recovered from the point
+   of failure with RESEND).
+
+   To use streaming on an unreliable connection, you must tell both
+   Kermits that the connection is reliable:
+
+  kermit -I
+
+   or:
+
+  C-Kermit> set reliable on
+
+   In this case, it will probably be necessary to prefix some control
+   characters, for example if your connection is through a terminal
+   server that has an escape character. Most Cisco terminal servers, for
+   example, require Ctrl-^ (30, as well as its high-bit equivalent, 158)
+   to be prefixed. To unprefix these, you'll need to defeat the "clear
+   channel" feature:
+
+  C-Kermit> set reliable on
+  C-Kermit> set clear-channel off
+  C-Kermit> set prefixing none
+  C-Kermit> set control prefix 1 13 30 158 ; and whatever else is necessary
+
+   Dialup trials were done using fixed large window and packet sizes.
+   They compare uploading and downloading of two common types of files,
+   with and without streaming. Configuration:
+
+     HP-9000/715/33 -- 57600bps, RTS/CTS -- USR Courier V.34 --
+     V.34+V.42, 31200bps -- USR V.34+ Rackmount -- 57600bps, RTS/CTS --
+     Cisco terminal server -- Solaris 2.5.1. Packet size = 8000, Window
+     Size = 30, Control Character Unprefixing Minimal (but including the
+     Cisco escape character).
+
+   Since this is not a truly reliable connection, a few trials failed
+   when a bad packet was received (most likely due to UART overruns); the
+   failure was graceful and immediate, and the message was informative.
+   The results of ten successful trials uploading and downloading the two
+   files with and without streaming are:
+
+            Streaming..
+            Off    On
+   Upload   5194   5565   txt (= C source code, 78K)
+            3135   3406   gz  (= gzip file, compressed, 85K)
+ Download   5194   5565   txt
+            3041   3406   gz
+
+   Each CPS figure is the mean of 10 results.
+
+   A brief test was also performed on a LAT-based dialout connection from
+   a VAX 3100 with VMS 5.5 to a USR Courier V.34 connected to a DECserver
+   700 at 19200 bps. The 1-MB Sparc executable downloaded from a Sun to
+   the VAX at 1100cps without streaming and 1900cps with streaming, using
+   8000-byte packets, 30 window slots, and minimal prefixing in both
+   cases.
+     _________________________________________________________________
+
+    4.20.2.5. Streaming on X.25 Connections
+
+   We have only limited access to X.25 networks. One trial was performed
+   in which the 1MB Solaris 2.4 Sparc executable was transferred over a
+   SunLink X.25 connection; nothing is known about the actual physical
+   connection. With a packet length of 8000 and a window size of 30, the
+   file transferred at 6400 cps (using a maximum of 6 window slots). With
+   the same packet length, but with streaming, it transferred without
+   mishap at 6710 cps, about 5% faster.
+     _________________________________________________________________
+
+    4.20.3. Streaming - Preliminary Conclusions
+
+   The results vary with the particular connection, but are good overall.
+   Although numerous lower-level tricks can be used to improve
+   performance on specific platforms or connection methods, streaming
+   occurs at a high, system-independent level of the Kermit protocol and
+   therefore can apply to all types of platforms and (reliable)
+   connections transparently.
+     _________________________________________________________________
+
+  4.21. The TRANSMIT Command
+
+   Prior to C-Kermit 7.0, the TRANSMIT command transmitted in text or
+   binary mode according to SET FILE TYPE { TEXT, BINARY }. But now that
+   binary mode is likely to be the default for protocol transfers, it is
+   evident that this not also an appropriate default for TRANSMIT, since
+   binary-mode TRANSMIT is a rather specialized and tricky operation.
+   Therefore, TRANSMIT defaults to text mode always, regardless of the
+   FILE TYPE setting.
+
+   C-Kermit 7.0 expands the capabilities of the TRANSMIT command by
+   adding the following switches (see [524]Section 1.5). The new syntax
+   is:
+
+  TRANSMIT [ switches... ] filename
+
+   Zero or more switches may be included:
+
+   /PIPE
+          When /PIPE is included, "filename" is interpreted as a system
+          command or program whose output is to be sent. Synonym:
+          /COMMAND. Example:
+
+  transmit /pipe finger
+
+          You may enclose the command in braces, but you don't have to:
+
+  xmit /pipe {ls -l | sort -r +0.22 -0.32 | head}
+
+   /BINARY
+          Transmits the file (or pipe output) in binary mode.
+
+   /TEXT
+          Transmits the file (or pipe output) in line-oriented text mode.
+          Current FILE CHARACTER-SET and TERMINAL CHARACTER-SET
+          selections govern translation. Default.
+
+   /TRANSPARENT
+          Specifies text mode without character-set translation, no
+          matter what the FILE and TERMINAL CHARACTER-SET selections are.
+
+   /NOWAIT
+          This is equivalent to SET TRANSMIT PROMPT 0, but for this
+          TRANSMIT command only. Applies only to text mode; it means to
+          not wait for any kind of echo or turnaround character after
+          sending a line before sending the next line. (Normally Kermit
+          waits for a linefeed.)
+
+   When TRANSMIT ECHO is ON, C-Kermit tries to read back the echo of each
+   character that is sent. Prior to C-Kermit 7.0, 1 second was allowed
+   for each echo to appear; if it didn't show up in a second, the
+   TRANSMIT command would fail. Similarly for the TRANSMIT PROMPT
+   character. However, with today's congested Internet connections, etc,
+   more time is often needed:
+
+   SET TRANSMIT TIMEOUT number
+   Specifies the number of seconds to wait for an echo or the prompt
+   character when TRANSMIT PROMPT is nonzero; the default wait is 1
+   second. If you specify 0, the wait is indefinite. When a timeout
+   interval of 0 is specified, and a desired echo or prompt does not show
+   up, the TRANSMIT command will not terminate until or unless you
+   interrupt it with Ctrl-C; use SET TRANSMIT TIMEOUT 0 with caution.
+
+   Note: to blast a file out the communications connection without any
+   kind of synchronization or timeouts or other manner of checking, use:
+
+  SET TRANSMIT ECHO OFF
+  SET TRANSMIT PROMPT 0 (or include the /NOWAIT switch)
+  SET TRANSMIT PAUSE 0
+  TRANSMIT [ switches ] filename
+
+   In this case, text-file transmission is not-line oriented and large
+   blocks can be sent, resulting in a significant performance improvement
+   over line-at-at-time transmission. Successful operation depends (even
+   more than usual for the TRANSMIT command!) on a clean connection with
+   effective flow control.
+
+   For details on TRANSMIT and character sets, see [525]Section 6.6.5.4.
+     _________________________________________________________________
+
+  4.22. Coping with Faulty Kermit Implementations
+
+   Kermit protocol has been implemented in quite a few third-party
+   commercial, shareware, and freeware software packages, with varying
+   degrees of success. In most cases operation is satisfactory but slow
+   -- only the bare minimum subset of the protocol is available -- short
+   packets, no sliding windows, no attributes, etc. In other cases, the
+   implementation is incorrect, resulting in failures at the initial
+   negotiation stage or corrupted files.
+
+   C-Kermit 7.0 and Kermit 95 1.1.19 include some new defense mechanisms
+   to help cope with the most common situations. However, bear in mind
+   there is only so much we can do in such cases -- the responsibility
+   for fixing the problem lies with the maker of the faulty software.
+     _________________________________________________________________
+
+    4.22.1. Failure to Accept Modern Negotiation Strings
+
+   The published Kermit protocol specification states that new fields can
+   be added to the parameter negotiation string. These are to be ignored
+   by any Kermit implementation that does not understand them; this is
+   what makes the Kermit protocol extensible. Unfortunately, some Kermit
+   implementations become confused (or worse) when receiving a
+   negotiation string longer than the one they expect. You can try
+   working around such problems by telling Kermit to shorten its
+   negotiation string (and thus disable the corresponding new features):
+
+  SET SEND NEGOTIATION-STRING-MAX-LENGTH number
+
+   Try a number like 10. If that doesn't work, try 9, 8, 7, 6, and so on.
+     _________________________________________________________________
+
+    4.22.2. Failure to Negotiate 8th-bit Prefixing
+
+   The published Kermit protocol specification states that 8th-bit
+   prefixing (which allows transfer of 8-bit data over a 7-bit
+   connection) occurs if the file sender puts a valid prefix character
+   (normally "&") in the 8th-bit-prefix field of the negotiation string,
+   and the receiver puts either a letter "Y" or the same prefix
+   character. At least one faulty Kermit implementation exists that does
+   not accept the letter "Y". To force C-Kermit / K-95 to reply with the
+   other Kermit's prefix character rather than a "Y", give the following
+   (invisible) command:
+
+  SET Q8FLAG ON
+
+   Use SET Q8FLAG OFF to restore the normal behavior.
+     _________________________________________________________________
+
+    4.22.3. Corrupt Files
+
+   Refer to [526]Section 4.22.2. Some Kermit implementations mistakenly
+   interpret the "Y" as a prefix character. Then, whenever a letter Y
+   appears in the data, the Y and the character that follows it are
+   replaced by a garbage character. At this writing, we are not sure if
+   there is any solution, but try "set send negotiation-string-max-length
+   6" and/or "set q8flag on".
+
+   File corruption can also occur when control characters within the file
+   data are sent without prefixing, as at least some are by default in
+   C-Kermit 7.0 and K-95. Some Kermit implementations do not handle
+   incoming "bare" control characters. To work around, "set prefixing
+   all".
+     _________________________________________________________________
+
+    4.22.4. Spurious Cancellations
+
+   The Kermit protocol specification states that if an ACK to a Data
+   packet contains X in its data field, the transfer of the current file
+   is canceled, and if it contains a Z, the entire transfer is canceled.
+   At least one overzealous Kermit implementation applies this rule to
+   non-Data packets as well, the typical symptom being that any attempt
+   to transfer a file whose name begins with X or Z results in
+   cancellation. This is because the file receiver typically sends back
+   the name under which it stored the file (which might not be the same
+   as the name it was sent with) in the ACK to the File Header packet.
+   This is information only and should not cause cancellation. To work
+   around the problem, use:
+
+  SET F-ACK-BUG { ON, OFF }
+
+   ON tells Kermit not to send back the filename in the ACK to the file
+   header packet as it normally would do (OFF puts Kermit back to normal
+   after using ON).
+
+   A variation on the this bug occurs in an obscure Kermit program for
+   MUMPS: When this Kermit program sends a file called (say) FOO.BAR, it
+   requires that the ACK to its F packet contain exactly the same name,
+   FOO.BAR. However, C-Kermit likes to send back the full pathname,
+   causing the MUMPS Kermit to fail. SET F-ACK-BUG ON doesn't help here.
+   So a separate command has been added to handle this situation:
+
+  SET F-ACK-PATH { ON, OFF }
+
+   Normally it is ON (regardless of the SET SEND PATHNAMES setting). Use
+   SET F-ACK-PATH OFF to instruct Kermit to send back only the filename
+   without the path in the ACK to the F packet.
+     _________________________________________________________________
+
+    4.22.5. Spurious Refusals
+
+   Some Kermit implementations, notably PDP-11 Kermit 3.60 and earlier,
+   have bugs in their handling of Attribute packets that can cause
+   unwarranted refusal of incoming files, e.g. based on date or size.
+   This can be worked around by telling one or both of the Kermit
+   partners to:
+
+  SET ATTRIBUTES OFF
+     _________________________________________________________________
+
+    4.22.6. Failures during the Data Transfer Phase
+
+   This can be caused by control-character unprefixing ([527]Section
+   4.22.3 ), and fixed by:
+
+  SET PREFIXING ALL
+
+   It can also have numerous other causes, explained in Chapter 10 of
+   [528]Using C-Kermit: the connection is not 8-bit transparent (so use
+   "set parity space" or somesuch), inadequate flow control, etc. Consult
+   the manual.
+     _________________________________________________________________
+
+    4.22.7. Fractured Filenames
+
+   At least one well-known PC-based communications package negotiates
+   data compression, which (according to the protocol specification)
+   applies to both the filename and the file data, but then fails to
+   decompress the filename. Example: C-Kermit sends a file called
+   R000101.DAT (where 000101 might be non-Y2K-wise YYMMDD notation), and
+   the package in question stores the files as R~#0101.DAT. Workaround:
+   Tell C-Kermit to SET REPEAT COUNTS OFF.
+     _________________________________________________________________
+
+    4.22.8. Bad File Dates
+
+   At least one well-known PC-based communications package negotiates the
+   passing of file timestamps from sender to receiver, but when it is
+   sending files, it always gives them a timestamp of 1 February 1970.
+   Workaround: tell C-Kermit to SET ATTRIBUTE DATE OFF. You don't get the
+   file's real date, but you also don't get 1 Feb 1970; instead the file
+   gets the current date and time.
+     _________________________________________________________________
+
+  4.23. File Transfer Recovery
+
+   Prior to C-Kermit 7.0, RESEND (SEND /RECOVER) and REGET (GET /RECOVER)
+   refused to work if FILE TYPE was not BINARY or the /BINARY switch was
+   not included. Now these commands include an implied /BINARY switch,
+   meaning they set the file type to binary for the duration of the
+   command automatically.
+
+   In the client/server arrangement, this also forces the server into
+   binary mode (if it is C-Kermit 7.0 or greater, or K95 1.1.19 or
+   greater) so the recovery operation proceeds, just as you asked and
+   expected.
+
+   BUT... Just as before, the results are correct only under the
+   following conditions:
+
+     * If the prior interrupted transfer was also in binary mode; or:
+     * If the prior transfer was in text mode and the other computer was
+       a "like platform" (e.g. UNIX-to-UNIX, Windows-to-Windows,
+       DOS-to-Windows) AND there was no character-set translation (i.e.
+       TRANSFER CHARACTER-SET was TRANSPARENT).
+
+   Note that these circumstances are more likely to obtain in C-Kermit
+   7.0, in which:
+
+     * The default FILE TYPE in C-Kermit 7.0 is BINARY.
+     * The default FILE INCOMPLETE setting is AUTO, which means KEEP if
+       the transfer is in binary mode, DISCARD otherwise.
+     * C-Kermit 7.0, Kermit 95 1.1.17, and MS-DOS Kermit 3.15 and later
+       can recognize "like platforms" and switch into binary mode
+       automatically. Transfers between like platforms are always binary
+       unless character-set translation has been requested, and then is
+       still binary for all files whose names match a binary pattern,
+       unless the automatic mechanisms have been disabled (with a /TEXT
+       switch, or with SET TRANSFER MODE MANUAL).
+     * SEND /BINARY and GET /BINARY always force binary-mode transfers,
+       even when FILE TYPE is TEXT, even when TRANSFER MODE is AUTOMATIC,
+       even when PATTERNS are ON and the file's name matches a text
+       pattern.
+
+   But also note that the automatic client/server transfer-mode
+   adjustments do not work with versions of C-Kermit prior to 7.0 or K95
+   prior to 1.1.16.
+
+   If the prior transfer was in text mode:
+
+     * If text-mode transfers between the two platforms are
+       "length-changing" (as they are between UNIX -- which terminates
+       text lines with LF -- and DOS or Windows -- which terminates text
+       lines with CRLF), the recovered file will be corrupt.
+     * If text-mode transfers between the two platforms are not
+       length-changing, but character-set translation was active in the
+       prior transfer, the result will be a file in which the first part
+       has translated characters and the second part does not.
+
+   But in C-Kermit 7.0 and K95 1.1.19 and later, incompletely transferred
+   text files are not kept unless you change the default. But if you have
+   done this, and you have an incompletely transferred text file, you'll
+   need to:
+
+     * Transfer the whole file again in text mode, or:
+     * Use SEND /STARTING-AT: to recover the transfer at the correct
+       point; but you have to find out what that point is, as described
+       in the manual.
+
+   Kermit has no way of knowing whether the previous transfer was in text
+   or binary mode so it is your responsibility to choose the appropriate
+   recovery method.
+
+   If you use C-Kermit to maintain parallel directories on different
+   computers, using SET FILE COLLISION to transfer only those files that
+   changed since last time, and the files are big enough (or the
+   connection slow enough) to require SEND /RECOVER to resume interrupted
+   transfers, you should remember that SEND /RECOVER (RESEND) overrides
+   all FILE COLLISION settings. Therefore you should use SEND /RECOVER
+   (RESEND) only on the file that was interrupted, not the file group.
+   For example, if the original transfer was initiated with:
+
+  SEND *
+
+   and was interrupted, then after reestablishing your connection and
+   starting the Kermit receiver with SET FILE COLLISION UPDATE on the
+   remote end, use the following sequence at the sender to resume the
+   transfer:
+
+  SEND /RECOVER name-of-interrupted-file
+
+   and then:
+
+  SEND *
+
+   (In C-Kermit 7.0 and later, \v(filename) contains the name of the file
+   most recently transferred, as long you have not EXITed from Kermit or
+   changed directory, etc.
+     _________________________________________________________________
+
+  4.24. FILE COLLISION UPDATE Clarification
+
+   In UNIX, file modification dates are used when comparing the file date
+   with the date in the attribute packet. In VMS, however, the file
+   creation date is used. These two policies reflect the preferences of
+   the two user communities.
+
+   Also, remember that the file date/time given in the attribute packet
+   is the local time at the file sender. At present, no timezone
+   conversions are defined in or performed by the Kermit protocol. This
+   is primarily because this feature was designed at a time when many of
+   the systems where Kermit runs had no concept of timezone, and
+   therefore would be unable to convert (say, to/from GMT or UTC or Zulu
+   time).
+
+   As a consequence, some unexpected results might occur when
+   transferring files across timezones; e.g. commands on the target
+   system that are sensitive to file dates might work (UNIX "make",
+   backups, etc).
+
+   Timezone handling is deferred for a future release.
+     _________________________________________________________________
+
+  4.25. Autodownload Improvements
+
+   Refer to pages 164-165 of [529]Using C-Kermit about the hazards of
+   autodownload when C-Kermit is "in the middle". As of C-Kermit 7.0, no
+   more hazards. If C-Kermit has TERMINAL AUTODOWNLOAD ON and it detects
+   a packet of the current protocol type (Kermit or Zmodem), it "erases"
+   the visual aspect of the packet that would be seen by the terminal
+   (or, more to the point, the emulator, such as K95). This way, only
+   C-Kermit goes into RECEIVE mode, and not also the terminal emulator
+   through which C-Kermit is accessed. And therefore, it is no longer
+   necessary to SET TERMINAL AUTODOWNLOAD OFF to prevent multiple Kermits
+   from going into receive mode at once, but of course it is still
+   necessary to ensure that, when you have multiple Kermits in a chain,
+   that the desired one receives the autodownload.
+
+   The defaults have not been changed; Kermit 95 still has autodownload
+   ON by default, and C-Kermit has it OFF by default.
+     _________________________________________________________________
+
+  5. CLIENT/SERVER
+
+  5.0. Hints
+
+   If you use SET SERVER GET-PATH to set up your server, and the GET-PATH
+   does not include the server's current directory, clients can become
+   quite confused. For example, "remote dir oofa.txt" shows a file named
+   oofa.txt, but "get oofa.txt" fails. In this situation, you should
+   either DISABLE DIR or make your GET-PATH include the current
+   directory.
+     _________________________________________________________________
+
+  5.1. New Command-Line Options
+
+   The -G command-line option is like -g (GET), except the incoming file
+   is sent to standard output rather than written to disk.
+
+   The -I option ("Internet") is used to tell a remote C-Kermit program
+   that you are coming in via Internet Telnet or Rlogin and therefore
+   have a reliable connection. The -I option is equivalent to SET
+   RELIABLE ON and SET FLOW NONE.
+
+   The -O option ("Only One") tells C-Kermit to enter server mode but
+   then exit after the first client operation.
+
+   See [530]Section 9.3 for details.
+     _________________________________________________________________
+
+  5.2. New Client Commands
+
+   BYE and FINISH no longer try to do anything if a connection is not
+   active. Thus a sequence like "hangup" followed by "bye" or "finish"
+   will no longer get stuck in a long timeout-and-retransmission cycle,
+   nor will it try to open a new connection.
+
+   REMOTE EXIT
+          Similar to FINISH, except it ensures that the Kermit server
+          program exits back to the operating system or shell prompt.
+          (FINISH would return it to its interactive prompt if it was
+          started in interactive mode, and would cause it to exit if it
+          entered server mode via command-line option.) When C-Kermit is
+          to be the server, you can use { ENABLE, DISABLE } EXIT to
+          control the client's access to this feature.
+
+   REMOTE MKDIR directory-name
+          Tells the client to ask the server to create a directory with
+          the given name, which can be absolute or relative. The syntax
+          of the directory name depends on the Kermit server (see
+          [531]next section); in all cases, it can be in the syntax of
+          the system where the server is running (UNIX, VMS, DOS, etc)
+          but newer servers also accept UNIX syntax, no matter what the
+          underlying platform. The server will not execute this command
+          if (a) it does not understand it, (b) a DISABLE MKDIR command
+          has been given, or (c) a DISABLE CWD command has been given;
+          otherwise, the command is executed, but will fail if the
+          directory can not be created, in which cases most servers will
+          attempt to return a message giving the reason for failure. The
+          REMOTE MKDIR command succeeds if the remote directory is
+          created, or if it already exists and therefore does not need to
+          be created, and fails otherwise.
+
+   REMOTE RMDIR directory-name
+          Tells the client to ask the server to remove (delete) a
+          directory with the given name. The same considerations apply as
+          for REMOTE MKDIR.
+
+   REMOTE SET FILE INCOMPLETE { DISCARD, KEEP, AUTO }
+          Previously this was only available in its earlier form, REMOTE
+          SET INCOMPLETE (no FILE). The earlier form is still available,
+          but invisible. Also, AUTO was added, meaning KEEP if in binary
+          mode, DISCARD otherwise.
+
+   REMOTE SET TRANSFER MODE { AUTOMATIC, MANUAL }
+          Tells the client to ask the server to set the given
+          file-transfer mode. Automatic means (roughly): if the client
+          and the server are running on the same kind of computer (e.g.
+          both are on UNIX), then use binary mode automatically; if the
+          system types are different, use some other method to
+          automatically determine text or binary mode, such as filename
+          pattern matching. MANUAL means, in this context, obey the
+          client's FILE TYPE setting (TEXT or BINARY). Synonym: REMOTE
+          SET XFER MODE.
+
+   [ REMOTE ] QUERY KERMIT function(args...)
+          Prior to C-Kermit 7.0, the arguments were not evaluated
+          locally. Thus it was not possible to have the server run the
+          function with client-side variables as arguments. Now:
+
+  define \%a oofa.*
+  remote query kermit files(\%a)    ; Client's \%a
+  remote query kermit files(\\%a)   ; Server's \%a
+
+   [ REMOTE ] LOGIN [ user [ password ] ]
+          LOGIN is now a synonym for REMOTE LOGIN.
+
+   LOGOUT
+          This command, when given in local mode, is equivalent to REMOTE
+          LOGOUT. When given at the IKSD prompt, it logs out the IKSD.
+          When given at the C-Kermit prompt when it has no connection, it
+          does nothing.
+
+   Note that in C-Kermit 7.0, the REMOTE (or R) prefix is not required
+   for QUERY, since there is no local QUERY command. The new top-level
+   QUERY command does exactly what REMOTE QUERY (RQUERY) does.
+
+   All REMOTE commands now have single-word shortcuts:
+
+ Shortcut   Full Form
+  RASG       REMOTE ASSIGN
+  RCD        REMOTE CD
+  RCOPY      REMOTE COPY
+  RDEL       REMOTE DELETE
+  RDIR       REMOTE DIRECTORY
+  REXIT      REMOTE EXIT
+  RHELP      REMOTE HELP
+  RHOST      REMOTE HOST
+  RPWD       REMOTE PWD
+  RSET       REMOTE SET
+  etc.
+
+   The R prefix is not applied to LOGIN because there is already an
+   RLOGIN command with a different meaning. It is not applied to LOGOUT
+   either, since LOGOUT knows what to do in each case, and for symmetry
+   with LOGIN.
+     _________________________________________________________________
+
+    5.2.1. Remote Procedure Definitions and Calls
+
+   This is nothing new, but it might not be obvious... REMOTE ASSIGN and
+   REMOTE QUERY may be used to achieve remote procedure execution. The
+   remote procedure can be defined locally or remotely.
+
+   A remote procedure call is accomplished as noted in the previous
+   section:
+
+  [ remote ] query kermit function-name(args...)
+
+   This invokes any function that is built in to the Kermit server, e.g.:
+
+  [ remote ] query kermit size(foo.bar)
+
+   returns the size of the remote file, foo.bar.
+
+   Now note that C-Kermit includes an \fexecute() function, allowing it
+   to execute any macro as if it were a built-in function. So suppose
+   MYMACRO is the name of a macro defined in the server. You can execute
+   it from the client as follows (the redundant "remote" prefix is
+   omitted in the remaining examples):
+
+  query kermit execute(mymacro arg1 arg2...)
+
+   The return value, if any, is the value of the RETURN command that
+   terminated execution of the macro, for example:
+
+  define addtwonumbers return \feval(\%1+\%2)
+
+   The client invocation would be:
+
+  query kermit execute(addtwonumbers 3 4)
+  7
+
+   The result ("7" in this case) is also assigned to the client's
+   \v(query) variable.
+
+   To execute a remote system command or command procedure (shell script,
+   etc) use:
+
+  query kermit command(name args...)
+
+   Finally, suppose you want the client to send a macro to the server to
+   be executed on the server end. This is done as follows:
+
+  remote assign macroname definition
+  query kermit execute(macroname arg1 arg2...)
+
+   Quoting is required if the definition contains formal parameters.
+     _________________________________________________________________
+
+  5.3. New Server Capabilities
+
+    5.3.1. Creating and Removing Directories
+
+   The C-Kermit 7.0 server responds to REMOTE MKDIR and REMOTE RMDIR
+   commands. The directory name may be in either the native format of the
+   server's computer, or in UNIX format. For example, a server running on
+   VMS with a current directory of [IVAN] can accept commands from the
+   client like:
+
+  remote mkdir olga         ; Makes [IVAN.OLGA] (nonspecific format)
+  remote mkdir .olga        ; Makes [IVAN.OLGA] (VMS format without brackets)
+  remote mkdir olga/        ; Makes [IVAN.OLGA] (UNIX relative format)
+  remote mkdir /ivan/olga   ; Makes [IVAN.OLGA] (UNIX absolute format)
+  remote mkdir [ivan.olga]  ; Makes [IVAN.OLGA] (VMS absolute format)
+  remote mkdir [.olga]      ; Makes [IVAN.OLGA] (VMS relative format)
+
+    5.3.1.1. Creating Directories
+
+   If a directory name is given that contains more than one segment that
+   does not exist, the server attempts to create all the segments. For
+   example, if the client says:
+
+  REMOTE MKDIR letters/angry
+
+   a "letters" subdirectory is created in the server's current directory
+   if it does not already exist, and then an "angry" subdirectory is
+   created beneath it, if it does not already have one. This can repeated
+   to any reasonable depth:
+
+  REMOTE MKDIR a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/z/y/z
+
+    5.3.1.2. Removing Directories
+
+   When attempting to execute a REMOTE RMDIR, the server can remove only
+   a single directory, not an entire sequence or tree. The system service
+   that is called to remove the directory generally requires not only
+   that the server process has write delete access, but also that the
+   directory contain no files.
+
+   In the future, a REMOTE RMDIR /RECURSIVE command (and the accompanying
+   protocol) might be added. For now, use the equivalent REMOTE HOST
+   command(s), if any.
+     _________________________________________________________________
+
+    5.3.2. Directory Listings
+
+   Directory listings are generated by C-Kermit itself, rather than by
+   running the underlying system's directory command. Some control over
+   the listing format can be obtained with the SET OPTIONS DIRECTORY
+   command ([532]Section 4.5.1). The following options affect listings
+   sent by the server: /[NO]HEADING, /[NO]DOTFILES, and /[NO]BACKUP. In
+   UNIX and VMS, the listing is always sorted by filename. There is, at
+   present, no protocol defined for the client to request listing options
+   of the server; this might be added in the future.
+
+   The server's directory listings are in the following format:
+
+   Protection or permissions:
+          In UNIX and OS-9, this is a 10-character field, left adjusted.
+          In VMS it is a 22-character field, left-adjusted. In each case,
+          the protection / permission codes are shown in the server
+          platform's native format. In other operating systems, this
+          field is not shown.
+
+   Size in bytes:
+          This is always a 10-character field. The file's size is shown
+          as a decimal number, right adjusted in the field. If the file
+          is a directory and its size can not be obtained, the size is
+          shown as "<DIR>". Two blanks follow this field.
+
+   Date:
+          Always in yyyy-mm-dd hh:mm:ss numeric format, and therefore 19
+          characters long. If the file's date/time can't be obtained,
+          zeros (0) are shown for all the digits. This field is followed
+          by two blanks.
+
+   Filename:
+          This field extends to the end of the line. Filenames are shown
+          relative to the server's current directory. In UNIX, symbolic
+          links are shown as they are in an "ls -l" listing as "linkname
+          -> filename".
+
+   In UNIX and VMS, listings are returned by the server in alphabetical
+   order of filename. There are presently no other sort or selection
+   options.
+
+   However, since these are fixed-field listings, all fields can be used
+   as sort keys by external sort programs. Note, in particular, that the
+   format used for the date allows a normal lexical on that field to
+   achieve the date ordering. For example, let's assume we have a UNIX
+   client and a UNIX server. In this case, the server's listing has the
+   date in columns 22-40, and thus could be sorted by the UNIX sort
+   program using "sort +0.22 -0.40" or in reverse order by "sort +0.22
+   -0.40r".
+
+   Since the UNIX client can pipe responses to REMOTE commands through
+   filters, any desired sorting can be accomplished this way, for
+   example:
+
+C-Kermit> remote directory | sort +0.22 -0.40
+
+   You can also sort by size:
+
+  C-Kermit> remote directory | sort +0.11 -0.19
+
+   You can use sort options to select reverse or ascending order. "man
+   sort" (in UNIX) for more information. And of course, you can pipe
+   these listings through any other filter of your choice, such as grep
+   to skip unwanted lines.
+     _________________________________________________________________
+
+  5.4. Syntax for Remote Filenames with Embedded Spaces
+
+   C-Kermit and K95, when in server mode, assume that any spaces in the
+   file specification in an incoming GET command are filename separators.
+   Thus if the client gives a command like:
+
+  get {oofa.txt oofa.bin}
+
+   or, equivalently:
+
+  mget oofa.txt oofa.bin
+
+   the server tries to send the two files, oofa.txt and oofa.bin. But
+   what if you want the server to send you a file named, say:
+
+  D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL
+
+   How does the server know this is supposed to be one file and not
+   seven? In this case, you need to the send file name to the server
+   enclosed in either curly braces:
+
+  {D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL}
+
+   or ASCII doublequotes:
+
+  "D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL"
+
+   The method for doing this depends on your client. If your client is
+   C-Kermit 7.0, any recent version of Kermit 95, or MS-DOS Kermit 3.16,
+   then you have to enclose the name in braces just so the client can
+   parse it, so to send braces or doublequotes to the server, you must
+   put them inside the first, outside pair of braces. And you also need
+   to double the backslashes to prevent them from being interpreted:
+
+  get {{D:\\HP OfficeJet 500\\Images\\My Pretty Picture Dot PCL}}
+  get {"D:\\HP OfficeJet 500\\Images\\My Pretty Picture Dot PCL"}
+
+   To get around the requirement to double backslashes in literal
+   filenames, of course you can also use:
+
+  set command quoting off
+  get {{D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL}}
+  get {"D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL"}
+  set command quoting on
+
+   If you are giving a "kermit" command to the UNIX shell, you have to
+   observe the shell's quoting rules, something like this:
+
+  kermit -ig "{D:\HP OfficeJet 500\Images\My Pretty Picture Dot PCL}"
+
+   Here, the quotes go on the outside so UNIX will pass the entire
+   filename, spaces, braces, and all, as a single argument to Kermit, and
+   the backslashes are not doubled because (a) the UNIX shell ignores
+   them since they are in a quoted string, and (b) Kermit ignores them
+   since the interactive command parser is not activated in this case.
+     _________________________________________________________________
+
+  5.5. Automatic Orientation Messages upon Directory Change
+
+   C-Kermit 7.0, when acting as a server, can send an orientation message
+   to the client whenever the server directory changes. For example, when
+   the client gives a REMOTE CD command, the server sends the contents of
+   the new directory's "Read Me" file to the client's screen. The
+   following commands govern this feature:
+
+   SET SERVER CD-MESSAGE FILE name
+          Given to the servr, allows the message-file name to be
+          specified at runtime. A list of names to look for can be given
+          in the following format:
+
+  {{name1}{name2}{name3}{...}}
+
+          e.g. SET SERVER CD-MESSAGE FILE
+          {{./.readme}{README.TXT}{READ.ME}}
+
+   REMOTE SET SERVER CD-MESSAGE { ON, OFF }
+          Given to the client, lets the client control whether the server
+          sends automatic CD messages.
+
+   SHOW SERVER
+          Given to server, includes CD-Message status.
+
+   The default CD message file name is system dependent. SHOW CD or SHOW
+   SERVER displays the list. Also see [533]Section 4.5.2.
+     _________________________________________________________________
+
+  5.6. New Server Controls
+
+   DISABLE ENABLE
+          Allows the server to configured such that DISABLEd features can
+          not be re-enabled by any means -- e.g. if the client is somehow
+          able to get the server into command mode. Once DISABLEd, ENABLE
+          can not be re-ENABLEd.
+
+   SET SERVER IDLE-TIMEOUT seconds
+          This was available previously in Kermit 95 only. Now it can be
+          used in C-Kermit also to specify a maximum number of seconds
+          the server is allowed to be idle before exiting server mode. 0
+          seconds means no idle timeout. In C-Kermit (but not K-95), SET
+          SERVER TIMEOUT and SET SERVER IDLE-TIMEOUT are mutually
+          exclusive -- you can have one or the other (or neither), but
+          not both. (Server timeouts are for the benefit of primitive
+          Kermit clients that are not capable of timing out on their own;
+          to our knowledge, no such clients are still in circulation.)
+
+   SET SERVER KEEPALIVE { ON, OFF }
+          (See next section).
+     _________________________________________________________________
+
+  5.7. Timeouts during REMOTE HOST Command Execution
+
+   Prior to C-Kermit 7.0, the C-Kermit server would block waiting for
+   output from a system command invoked via REMOTE HOST from the client.
+   If the system command took a long time to execute, the client would
+   time out and send NAK packets. If the command took too long, the
+   client would reach its retry limit and give up. Even if it didn't, the
+   NAKs would cause unnecessary retransmissions.
+
+   In version 7.0, the C-Kermit server (VMS and select()-capable UNIX
+   versions only), sends "keepalive packets" (empty data packets) once
+   per second while waiting for the system command to complete. This
+   procedure should be entirely transparent to the Kermit client, and
+   should prevent the unwanted timeouts and NAKs. When C-Kermit 7.0
+   itself (or K95 1.1.19) is the client, it prints dots to show the
+   keepalive packets.
+
+   The keepalive feature can be turned off and on with:
+
+  SET SERVER KEEPALIVE { ON, OFF }
+
+   Normally it should be on. Turn it off it if causes trouble with the
+   client, or if it seems to slow down the server (as it might on some
+   platforms under certain circumstances).
+     _________________________________________________________________
+
+  6. INTERNATIONAL CHARACTER SETS
+
+   Support for several new single-byte character sets was added in
+   C-Kermit 7.0. Unicode / ISO 10646 is not yet supported, but is a high
+   priority for forthcoming releases.
+
+  6.0. ISO 8859-15 Latin Alphabet 9
+
+   To accommodate the Euro currency symbol, and to correct several other
+   longstanding problems with ISO Latin Alphabet 1, ISO 8859-15 Latin
+   Alphabet 9 was issued in May 1998. It is supported by C-Kermit 7.0 as
+   a transfer character set, a file character set, and a terminal
+   character set. Translations that preserve the new characters are
+   available between Latin-9 and several other sets including:
+
+  PC Code Page 858         (Western European languages, similar to CP850)
+  Windows Code Page 1252   (Western European languages, similar to Latin-1)
+  Windows Code Page 1250   (Eastern European languages, similar to Latin-2)
+
+   The Latin-9 transfer character set also allows for the OE digraph
+   character, used primarily in French, to be preserved in transfers
+   involving the DEC MCS or NeXT character sets.
+
+   The Euro character is also present in the Universal Character Set,
+   described in [534]Section 6.6.
+
+  6.1. The HP-Roman8 Character Set
+
+   The HP-Roman8 character set is supported in C-Kermit 6.0 and later but
+   was omitted from Table VII-4 in the 2nd Edition of Using C-Kermit due
+   to lack of space. It is listed in [535]Appendix III.
+
+  6.2. Greek Character Sets
+
+   Greek character sets were added in 6.1:
+
+  SET FILE CHARACTER-SET { CP869, ELOT927, GREEK-ISO }
+  SET TRANSFER CHARACTER-SET { GREEK-ISO }
+
+   GREEK-ISO is ISO 8859-7, which the same as ELOT 928.
+
+   The new Greek character sets are listed in [536]Appendix III.
+
+  6.3. Additional Latin-2 Character Sets
+
+   The following have been added as FILE and TERMINAL CHARACTER-SETs:
+
+   MAZOVIA-PC
+          A PC code page used in Poland, equivalent to CP437, but with 18
+          substitutions needed for Polish.
+
+   CP1250
+          The Windows Latin 2 Code Page. Equivalent to ISO 8859-2, but
+          with different encoding.
+
+  6.4. Additional Cyrillic Character Sets
+
+   The following have been added as FILE and TERMINAL CHARACTER-SETs:
+
+   BULGARIA-PC
+          This is the Cyrillic PC code page used in Bulgaria, where it is
+          called Code Page 856. It is attributed to a company called
+          DATEC, Inc, but CP856 is not a proper designation, since it
+          refers to a Hebrew Code Page (see the IBM Registry).
+
+   CP855
+          This PC Code Page contains all the Cyrillic letters that are
+          also in ISO 8859-5, and is therefore useful for non-Russian
+          Cyrillic text (Ukrainian, Belorussian, etc), unlike CP866,
+          which has a smaller repertoire of Cyrillic letters.
+
+   CP1251
+          The Windows Cyrillic Code Page. Equivalent to CP855, but with
+          different encoding.
+
+   KOI8R
+          An extension to "Old KOI-8" that adds upper and lower case
+          Cyrillic letter Io (looks like Roman E with diaeresis) plus a
+          selection of box-drawing characters to columns 8 through 11,
+          which are vacant in original Old KOI-8. KOI8-R is used for the
+          Russian language. It is specified in [537]RFC 1489.
+
+   KOI8U
+          A similar extension of Old KOI-8, but for Ukrainian. It is
+          specified in [538]RFC 2319.
+     _________________________________________________________________
+
+  6.5. Automatic Character-Set Switching
+
+   Prior to version 7.0, C-Kermit's file character-set always had to be
+   set explicitly. In 7.0 and later, it is set automatically when:
+
+    1. This feature is enabled (as it is unless you disable it).
+    2. An incoming text-mode transfer includes a transfer-character-set
+       announcer and you have not previously given a SET FILE
+       CHARACTER-SET command. In this case, C-Kermit switches to an
+       appropriate file character set. For example, on an HP-UX
+       workstation, an incoming Latin-1 file automatically selects
+       HP-Roman8 for the local copy of the file; in Data General AOS/VS,
+       it would select DG International.
+    3. You give a SET TRANSFER CHARACTER-SET command without having
+       previously specified a FILE CHARACTER-SET. An appropriate file
+       character-set is chosen automatically.
+
+   In addition, when you give a SET FILE CHARACTER-SET command, the
+   appropriate transfer character-set is automatically chosen, to be used
+   when you are sending files (but this does not override the one
+   announced by the sender when you are receiving files).
+
+   You might not agree about what is "appropriate", so of course you can
+   disable or change all of the above actions.
+
+   You can disable (or re-enable) the new automatic character-set
+   switching feature in each direction separately:
+
+   SET RECEIVE CHARACTER-SET-SELECTION { AUTOMATIC, MANUAL }
+          AUTOMATIC is the default, causing the behavior described above
+          when an incoming file arrives. Choose MANUAL to defeat this
+          behavior and force your current FILE CHARACTER-SET setting to
+          be used, no matter what it is. Note that SET RECEIVE
+          CHARACTER-SET MANUAL does not disable recognition of the
+          incoming transfer character-set announcer, and translation from
+          the corresponding character-set to your current file
+          character-set. To disable that, use SET ATTRIBUTE CHARACTER-SET
+          OFF.
+
+   SET SEND CHARACTER-SET-SELECTION { AUTOMATIC, MANUAL }
+          Again AUTOMATIC is the default, causing the behavior described
+          above when you give a SET { FILE, TRANSFER } CHARACTER-SET
+          command. Use MANUAL to allow you to specify the transfer and
+          file character-sets independently.
+
+   SHOW CHARACTER-SETS
+          Tells settings of { SEND, RECEIVE } CHARACTER-SET-SELECTION.
+
+   Normally, however, it is more convenient to leave automatic switching
+   active, and change any associations that are not appropriate for your
+   application, area, or country. The commands are:
+
+   SHOW ASSOCIATIONS
+          This command lists all the associations in each direction: for
+          each possible transfer character-set, it lists the associated
+          file character-set, and vice versa. These are two separate and
+          independent lists.
+
+   ASSOCIATE TRANSFER-CHARACTER-SET name1 [ name2 ]
+          Changes the association for the transfer character-set name1 to
+          be the file character-set name2. If name2 is omitted, automatic
+          switching is disabled for this transfer character-set only.
+
+   ASSOCIATE FILE-CHARACTER-SET name1 [ name2 ]
+          Changes the association for the file character-set name1 to be
+          the transfer character-set name2. If name2 is omitted,
+          automatic switching is disabled for this file character-set
+          only.
+     _________________________________________________________________
+
+  6.6. UNICODE
+
+   C-Kermit 7.0 adds support for Unicode, the Universal Character Set,
+   for:
+
+     * File Transfer (SEND, RECEIVE, GET, etc)
+     * Terminal connection (CONNECT)
+     * Unguarded file capture (LOG SESSION)
+     * Unguarded file transmission (TRANSMIT)
+     * Local file character-set conversion (TRANSLATE)
+
+   C-Kermit is not, however, a "Unicode application" in the sense that
+   its commands, messages, or user interface are Unicode. Rather, it is
+   "Unicode aware" in its ability to handle and convert Unicode text in
+   the course of file transfer and terminal connection, and you can also
+   use Kermit to convert local files between Unicode and other character
+   sets. TLA's:
+
+  BMP - Base Multilingual Plane
+  BOM - Byte Order Mark
+  CJK - Chinese, Japanese, and Korean
+  ISO - International Standards Organization
+  TLA - Three-Letter Acronym
+  UCS - Universal Character Set
+  UTF - UCS Transformation Format
+
+   Unicode and ISO 10646 are the coordinated and compatible corporate and
+   international standards for the Universal Character Set (UCS). Unlike
+   single-byte and even most multibyte character sets, the UCS can
+   represent all characters in every existing writing system. A flat
+   plain-text file encoded in some form of UCS can contain any mixture of
+   English, Spanish, Italian, German, Hebrew, Arabic, Greek, Russian,
+   Armenian, Georgian, Japanese, Chinese, Korean, Vietnamese, Tibetan,
+   Hindi, Bengali, Tamil, Thai, Ethiopic, and so on, plus scientific and
+   mathematical notation, as well as texts in Runes, Ogham, Glagolitic,
+   and other historic scripts.
+
+   The UCS already covers these scripts and many more, but it's an
+   evolving standard with efforts underway to accommodate even more
+   languages and writing systems. Support is growing for native UCS use
+   on many platforms and in many applications. The goal of the framers of
+   the UCS is for it to replace ASCII, the ISO Latin Alphabets, ISCII,
+   VISCII, the Chinese, Japanese, and Korean (CJK) multibyte sets, etc,
+   as well as the many private character sets in use today, in other
+   words to become *the* Universal Character Set.
+
+   Until that time, however, conversions between existing sets and the
+   UCS will be necessary when moving text between platforms and
+   applications. Now Kermit can help.
+     _________________________________________________________________
+
+    6.6.1. Overview of Unicode
+
+   For a more complete picture, please visit:
+
+  [539]http://www.unicode.org/
+
+   and access the various online introductions, FAQs, technical reports,
+   and other information. For greater depth, order the latest version of
+   the published Unicode Standard. The following overview contains a
+   great many oversimplifications and perhaps an opinion or two.
+
+   At present, the UCS is a 16-bit (2-byte) character set, but with
+   provisions to grow to a 4-byte set. UCS-2 refers to the two-byte set,
+   also called the Base Multilingual Plane (BMP), in which each character
+   has 16 bits, and therefore there are 2^16 = 65536 possible characters.
+   The first 128 characters are the same as US ASCII (C0 control
+   characters and DEL included), the next 32 are the C1 control
+   characters of ISO 6429, and the next 96 are the Right Half of ISO
+   8859-1 Latin Alphabet 1. The remaining tens of thousands of characters
+   are arranged newly for the UCS, usually (but not always) in sections
+   corresponding to existing standards, such as ISO Latin/Cyrillic, often
+   plus additional characters not appearing in the existing standards due
+   to lack of space (or other reasons).
+
+   ISO 10646 allows for additional planes, e.g. for Egyptian
+   hieroglyphics or ancient (or other esoteric) CJK characters, but these
+   planes are not yet defined and so we will say nothing more about them
+   here, except that their use will require the 4-byte form of UCS,
+   called UCS-4, in some form (more about "forms" in [540]Section 6.6.2).
+
+   Unicode and ISO 10646 are constantly under revision, mainly to add new
+   characters. The Unicode revision is denoted by a version number, such
+   as 1.0, 1.1, 2.0, 3.0. The ISO 10646 standard revision is identified
+   by Edition (such as ISO 10646-1 1993), plus reference to any
+   amendments. The first versions of these standards included encodings
+   for Korean Hangul syllables (Jamos); these encodings were changed in
+   version 1.1 of Unicode and by Amendment 5 to ISO 10646-1. The Unicode
+   Technical Committee and the ISO acknowledge that this was a bad thing
+   to do, and promise never change encodings or character names again,
+   since this poses serious problems for conformance and data
+   interchange.
+
+   A UCS-2 value is customarily written like this:
+
+  U+xxxx
+
+   where "xxxx" represents four hexadecimal digits, 0-9 and A-F. For
+   example, U+0041 is "A", U+00C1 is A-acute, U+042F is uppercase
+   Cyrillic "Ya", U+FB4F is Hebrew Ligature Alef Lamed, and U+FFFD is the
+   special character that means "not a character".
+
+   Most characters from widely-used alphabetic writing systems such as
+   the West European ones, Cyrillic, Greek, Hebrew, Vietnamese, etc, are
+   available in "precomposed" form; for example Uppercase Latin Letter A
+   with Acute Accent is a single character (as it is in Latin-1).
+   However, the UCS also permits composition of a base character with one
+   or more nonspacing diacritics. This means the same character can be
+   represented in more than one way, which can present problems in many
+   application areas, including transfer and character-set conversion of
+   text.
+
+   Conversion from ASCII or Latin-1 to UCS-2 text is "trivial": simply
+   insert a NUL (0) byte before each ASCII or Latin-1 byte. Converting in
+   the reverse direction (provided the UCS-2 file contains only U+0000 to
+   U+00FF) is equally simple (if we ignore the issue of composition):
+   remove every second (NUL) byte. Conversion of other character sets to
+   and from UCS, however, requires tables or algorithms specific to each
+   set. Nevertheless, the relatively transparent upwards compatibility
+   from ASCII and Latin-1, in which a very large share of the world's
+   textual data is encoded, gives the UCS an entree onto existing
+   platforms.
+
+   But the 2-byte format and the preponderance of NUL and other control
+   bytes in UCS-2 text pose problems for current applications and
+   transmission methods. And to make matters worse, different hardware
+   platforms store UCS-2 characters in different byte order. Thus a UCS-2
+   file transferred by FTP (or accessed via NFS, etc) between two
+   computers with different architecture might have its bytes in the
+   wrong order (or worse; see [541]Section 6.6.5.1 ).
+     _________________________________________________________________
+
+    6.6.2. UCS Byte Order
+
+   Consider the number 1. In an 8-bit byte, this would be represented by
+   the following series of 0- and 1-bits:
+
+  +-----------------+
+  | 0 0 0 0 0 0 0 1 |
+  +-----------------+
+
+   Therefore in a 16-bit "word" the representation might be:
+
+  +-----------------+-----------------+
+  | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 1 |
+  +-----------------+-----------------+
+
+   Now consider the number 256, which is 2 to the 8th power. The binary
+   representation is 100000000 (1 followed by 8 zeros). 256 would go into
+   a 16-bit word like this:
+
+  +-----------------+-----------------+
+  | 0 0 0 0 0 0 0 1 | 0 0 0 0 0 0 0 0 |
+  +-----------------+-----------------+
+
+   When a computer works this way, it is said to be Big Endian, meaning
+   it puts the most significant (biggest) byte first (on the "left") in a
+   16-bit word, and the least significant byte second (on the right).
+
+   However, some other computers have the opposite arrangement, called
+   Little Endian, in which 1 is:
+
+  +-----------------+-----------------+
+  | 0 0 0 0 0 0 0 1 | 0 0 0 0 0 0 0 0 |
+  +-----------------+-----------------+
+
+   and 256 is:
+
+  +-----------------+-----------------+
+  | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 1 |
+  +-----------------+-----------------+
+
+   Computers such as Sparc, MIPS, PA-RISC, and PowerPC are Big Endian,
+   whereas the PC and the Alpha are Little Endian. Endianness has never
+   been an issue with 7- or 8-bit characters, but it is with UCS
+   characters. It can be a tricky business to share or transfer a UCS-2
+   file between two different kinds of computers.
+
+   To alleviate (but not entirely solve) the problem, UCS-2 files are
+   supposed to begin with the Unicode character U+FEFF, Zero-Width
+   No-Break Space (ZWNBS). This is a kind of "no-op" (note: any such
+   assertion must normally be qualified with many "but ifs" and "excepts"
+   which are omitted here in the interest of brevity). If the bytes are
+   reversed the ZWNBS becomes U+FFFE, which is not (and never will be) a
+   defined UCS character. U+FEFF at the beginning of a UCS file is
+   therefore called a Byte Order Mark, or BOM.
+
+   Any application that creates a UCS-2 (or UTF-16, or UCS-4) file should
+   include a BOM, and any application that reads one should test for a
+   BOM, and if one is found, infer the byte order from it. This is a
+   convention, however -- not a standard or a requirement -- and
+   applications vary in their ability to handle BOMs and "backwards"
+   UCS-2 files.
+
+   Note that a BOM is useful only at the beginning of a file. If you
+   append one UCS-2 file to another, and both have BOMs, the internal BOM
+   is no longer a BOM. And if the byte orders of the two files differ,
+   then either the first part or the second will be backwards. (Various
+   other undesirable effects might also occur, not discussed here.)
+     _________________________________________________________________
+
+    6.6.2. UCS Transformation Formats
+
+   UCS textual data can be modified in various ways for transmission or
+   storage. Any officially sanctioned method of doing this is called a
+   UCS Transformation Format, or UTF. One such method, called UTF-16, is
+   essentially identical with UCS-2 except that it designates certain
+   code values as "escape sequences" (called surrogate pairs) to access
+   characters in other planes without having to use full UCS-4. We won't
+   discuss UTF-16 further here, since at the moment there are no other
+   planes. Several other UTF's (such as UTF-1, UTF-2, and UTF-7) have
+   fallen into disuse and are not discussed here. The most important
+   transformation format today is UTF-8.
+
+   UTF-8, so called because it "serializes" UCS-2 data into a stream of
+   8-bit bytes, is designed to allow the UCS to work with present-day
+   communications gear, computers, and software. The most important
+   properties of UTF-8 are that byte order is constant (no byte swapping)
+   and all (7-bit) ASCII characters represent themselves. Therefore
+   conversion between ASCII and UTF-8 is no conversion at all, and
+   applications or platforms (such as Plan 9 from Bell Labs) that use
+   UTF-8 "for everything" can still run traditional ASCII-only
+   applications and be accessed from them. In particular, unlike UCS-2,
+   ASCII characters are not padded with NUL bytes. But also unlike UCS-2,
+   there is no transparency for Latin-1 or any other non-ASCII character
+   set. Every non-ASCII UCS-2 character is represented by a sequence of 2
+   or 3 UTF-8 bytes. Thus UTF-8 is more compact than UCS-2 for text
+   containing a preponderance of ABC's (or other ASCII characters), about
+   the same as UCS-2 for other alphabetic scripts (Cyrillic, Roman,
+   Greek, etc), and larger than UCS-2 for Chinese, Japanese, and Korean.
+
+   The UTF-8 uncoding of the UCS has been adopted by the Internet as the
+   preferred character set for new applications, and is gradually being
+   retrofitted into traditional applications like FTP ([542]RFC 2640).
+     _________________________________________________________________
+
+    6.6.3. Conformance Levels
+
+   Although the Unicode and ISO 10646 standards both describe the same
+   character set, these standards differ in many ways, including their
+   stated requirements for conformance and their classification of
+   conformance levels.
+
+   Kermit has always abided by ISO character-set standards, including ISO
+   character-set designation and invocation methods. In adapting Unicode,
+   therefore, we had to choose from among the available ISO designations
+   which, in turn, correspond with ISO 10646 conformance levels. At
+   present, Kermit claims the lowest conformance level, 1, meaning
+   (roughly) that it does not handle combining forms and it does not
+   handle Korean Hangul Jamos (just as, at present, it does not handle
+   Korean in general). Note that ISO 10646 Conformance Levels 1 and 2
+   sidestep the issue of the code changes for Korean Hangul by announcing
+   non-support for Hangul regardless of encoding.
+
+   ISO 10646 Conformance Level 1 is approximately equivalent to Unicode
+   Normalization Form C (described in Unicode Technical Report 15,
+   incorporated into Unicode 3.0).
+
+   As noted in [543]Section 6.6.2, Kermit does not claim to support
+   UTF-16 at the present time, hence the UCS-2 nomenclature. Kermit
+   treats surrogates just as if they were any other UCS-2 characters,
+   rather than as escapes to other planes, which means that (except when
+   converting between UCS-2 and UTF-8) they are translated to "error"
+   characters, since (a) no other planes are defined yet (and if they
+   were, no other character sets supported by Kermit would encode their
+   characters), and (b) no valid surrogate character corresponds to any
+   other UCS-2 character.
+
+   A minor yet significant aspect of Unicode 3.0 and some recent
+   perturbation of ISO 10646-1 (probably Amendment 18, "Symbols and Other
+   Characters") is the addition of the Euro Sign at U+20AC. As noted in
+   [544]Section 6.0, Kermit's "Euro compliance" includes conversion
+   between Latin Alphabet 9 and various PC code pages. Text can also be
+   converted between UCS-2 or UTF-8 and any other Euro-compliant
+   character set (Latin-9, CP858, CP1250, CP1252) without loss of the
+   Euro Sign.
+     _________________________________________________________________
+
+    6.6.4. Relationship of Unicode with Kermit's Other Character Sets
+
+   Kermit's character sets are divided into two groups: single-byte sets
+   (such as Roman, Hebrew, Cyrillic, Greek) and multibyte (various
+   Japanese sets). The two groups are distinct since one normally would
+   not expect to convert Kanji ideograms to Roman (or other) letters, or
+   vice versa.
+
+   Unicode character-set conversion works with both groups, but obviously
+   the result depends on the repertoires of the source and destination
+   character-sets both including the characters in the file. For example,
+   you can translate a Hungarian text file between Latin-2 and Unicode,
+   but not between (say) Unicode and Latin/Greek. By the same token you
+   can convert Japanese text from Shift-JIS or EUC or JIS-7 to Unicode
+   and back, but you can't convert the same file to (say) Latin-1 if it
+   contains Japanese characters.
+
+     JIS-7 is equivalent to DEC Kanji and ISO-2022-JP except that the
+     latter two do not support halfwidth Katakana. Kermit treats all
+     three of these sets the same way, i.e. as JIS-7.
+
+   As noted, Kermit presently does not handle combining diacritics, and
+   so will not correctly convert UCS files that use them into a
+   single-byte character set. For example, if a UCS file contains Latin
+   Capital Letter A (U+0041) followed by Combining Acute Accent (U+0301),
+   the result will be a two-character sequence, A followed by another
+   character. This is what is meant by Conformance Level 1. (The
+   situation grows worse with multiple diacritics, since they can occur
+   in any order.)
+
+   A higher level of conformance is possible, in which "canonical
+   equivalences" are handled via algorithms and databases, at some
+   (perhaps considerable) cost in performance, since a fair amount of
+   additional code must be executed for every character during data
+   transfer (database lookup, sorting of combining sequences into
+   canonical order, etc). This can be added in future releases if there
+   is a need (but in many cases, pre- and postpostprocessing might be a
+   better option).
+
+   Within these constraints, Kermit converts between the UCS and its
+   other character sets. For example, a mixture of Russian and English
+   (and/or Dutch, or Latin) text can bet converted between the UCS and
+   ISO Latin/Cyrillic or KOI-8. But since Kermit does not presently
+   support Arabic character-set conversion, the new availability of UCS
+   conversion does not mean that Kermit can convert from Arabic UCS text
+   to some other character set, because Kermit does not support any other
+   character set that includes Arabic. Ditto for Thai, Armenian,
+   Georgian, Tibetan, Chinese, Korean, etc. However, Kermit CAN convert
+   Arabic (or any other script) between UCS-2 and UTF-8.
+
+   Considering Cyrillic more carefully, note that the UCS also contains
+   numerous Cyrillic characters not found in any of the Cyrillic sets
+   (ISO Latin/Cyrillic, KOI8, CP866, etc) that Kermit supports;
+   characters needed for Abkhasian, Yakut, Tatar, Bashkir, Altaic, Old
+   Church Slavonic, etc; UCS text containing any of these historic or
+   "extended" Cyrillic characters can not be converted to any of Kermit's
+   current single-byte Cyrillic sets without loss. The situation is
+   similar for Greek, Hebrew, etc, and even worse for Japanese since
+   Unicode contains thousands of Kanjis that are lacking from the
+   Japanese character sets based on JIS X 0208, such as EUC-JP, JIS-7,
+   and Shift-JIS.
+
+   In general, when converting from UCS to a single-byte set, there is
+   always the possibility of data loss, just as there is when converting
+   from any larger set to a smaller one. For example, if a UCS file
+   contains Devanagari characters, these characters will be lost when
+   converting to (say) Latin-1, just as Roman vowels with acute accents
+   are lost when converting from Latin-1 (an 8-bit set) to German ISO 646
+   (a 7-bit set).
+     _________________________________________________________________
+
+    6.6.5. Kermit's Unicode Features
+
+   C-Kermit can convert between UCS-2 or UTF-8 and any of its other
+   character sets, and also between UCS-2 and UTF-8. When converting
+   between UCS-2 or UTF-8 and a non-Unicode character set (such as
+   Latin-1), the UCS Line Separator (LS, U+2028) and Paragraph Separator
+   (PS, U+2029) characters are converted to the appropriate line
+   terminator (CR, LF, or CRLF). When converting from a non-Unicode set
+   to UCS-2 or UTF-8, however, line terminators are not converted to LS
+   or PS. This is in accordance with the recommendations of Unicode
+   Technical Report #13.
+
+   When C-Kermit starts, it tests the native byte order of the computer.
+   You can see the result in the SHOW FEATURES or SHOW FILE display. It's
+   also available in the variable \v(byteorder): 0 means Big Endian, 1
+   means Little Endian.
+
+   When UCS-2 is involved in file transfer or translation, the following
+   commands tell C-Kermit what to do about byte order:
+
+   SET FILE UCS BYTE-ORDER { BIG-ENDIAN, LITTLE-ENDIAN }
+          This is for reading UCS-2 files that don't have a BOM, and also
+          for writing UCS-2 files. If this command is not given, the
+          machine's native byte order is used when writing UCS-2 files,
+          and also when reading UCS-2 files that don't have a BOM.
+
+   SET FILE UCS BOM { ON, OFF }
+          This setting is used when creating UCS-2 files. A BOM is added
+          at the beginning by default. Use OFF to not add the BOM. This
+          command has no affect when writing files.
+
+   COPY /SWAP-BYTES sourcefile destinationfile
+          Use this for fixing a UCS-2 file whose bytes are in the wrong
+          order.
+
+   Use SHOW FILE to display the FILE UCS settings.
+
+   Please note, again, that C-Kermit's user interface, including its
+   script language, is not internationalized in any way. String
+   comparisons, case conversion, and so on, work only for US ASCII
+   (comparisons for equality work with other sets, but not
+   lexically-greater-or-less-than or caseless comparisons; even
+   comparisons for equality can fail when composed characters or byte
+   order are involved). String functions such as \findex() and
+   \fsubstring() that reference byte positions do just that; they won't
+   work with UTF-8 text that contains any non-ASCII characters, and they
+   will not work with UCS-2 text at all since they use C strings
+   internally, which are NUL-terminated. These are just a few examples to
+   illustrate that neither Unicode nor any other character-set beyond
+   ASCII is supported at the user-interface, command, or scripting level
+   in this version of C-Kermit.
+     _________________________________________________________________
+
+    6.6.5.1. File Transfer
+
+   Kermit supports both UCS-2 and UTF-8 as file and transfer character
+   sets in text-mode file transfer.
+
+   To select UCS-2 or UTF-8 as a file character-set, use:
+
+  SET FILE CHARACTER-SET { UCS2, UTF8 }
+
+   If you want to send a UCS-2 text file (or save an incoming file in
+   UCS-2 format), tell Kermit to:
+
+  SET FILE CHARACTER-SET UCS2
+
+   and if you want to send a UTF-8 text file (or store an incoming file
+   in UTF-8 format), tell Kermit to:
+
+  SET FILE CHARACTER-SET UTF8
+
+   When sending UCS-2 files, Kermit determines the byte order from the
+   BOM, if there is one (and if there is a BOM, it is stripped, i.e. not
+   sent). If there is no BOM, the byte order is the one specified in the
+   most recent SET FILE UCS BYTE-ORDER command, if any, otherwise the
+   computer's native byte order is assumed. When storing incoming files
+   as UCS-2, the byte order is according SET FILE UCS BYTE-ORDER, if
+   given, otherwise the native one; a BOM is written according to SET
+   FILE UCS BOM.
+
+   A transfer character-set should be chosen that includes all of the
+   characters in the source file. So, for example, if you are sending a
+   UCS-2 file containing only German-language text, your transfer
+   character-set can be Latin-1, Latin-2, Latin-9, UCS-2, or UTF-8. But
+   if you are sending a file that contains a combination of Hebrew and
+   Greek, your transfer character-set must be UCS-2 or UTF-8 if you don't
+   want to lose one script or the other. Furthermore, the transfer
+   character-set must be one that is supported by the receiving Kermit
+   program. Since UCS support is new, it is possible that the other
+   Kermit program (if it supports character sets at all) does not support
+   it, but does support single-byte sets such as Latin-1, Latin/Cyrillic,
+   etc.
+
+   To select UCS-2 or UTF-8 as a transfer character-set, use:
+
+  SET TRANSFER CHARACTER-SET { UCS2, UTF8 }
+
+   It is up to the receiving Kermit program to convert the transfer
+   format to its own local format, if necessary. If it does not
+   understand the UTF-8 or UCS-2 transfer character-set, and your file
+   can not be adequately represented by any single-byte transfer
+   character-set (such as Latin-1 or Latin/Cyrillic) then, if UTF-8
+   format is acceptable on the receiving computer, use UTF-8 as the
+   transfer character-set, with the receiver told to "set unknown-char
+   keep", or with the sender told to "set attribute char off". If you
+   want the file to be stored in UCS-2 format at the receiver, send it it
+   binary mode if the source file is also UCS-2, or else use the
+   TRANSLATE command (next section) to convert it to UCS-2 first, then
+   send it in binary mode. You should not use UCS-2 as a transfer
+   character-set in text-mode transfers to Kermit programs that don't
+   support it, because they are likely to corrupt the result the same way
+   FTP would (see the final paragraph of this section).
+
+   When UCS-2 is the transfer character set, it always goes into Kermit
+   packets in Big Endian format, with no BOM. As always, the transfer
+   character-set is announced by the sender to the receiver. The
+   announcement for UCS-2 is "I162" (ISO Registration 162 = UCS-2 Level
+   1) and by definition it is Big Endian (the standards say that when
+   UCS-2 is serialized into bytes, the order must be Big Endian). The
+   announcement for UTF-8 is "I190" (UTF-8 Level 1).
+
+   When receiving a file whose transfer character-set is UCS-2 or UTF-8,
+   you must choose the appropriate file character set for the result.
+   There is no way Kermit can do this for you automatically, since UCS
+   data can be in any script at all, or any combination.
+
+   In general, UTF-8 or UCS-2 should be chosen as a transfer
+   character-set if the source file is also encoded in some form of UCS
+   and it contains more than one script. But there are other situations
+   where where UTF-8 or UCS-2 offer advantages. For example, suppose the
+   source file is on a NeXTstation and the destination file is on VMS.
+   Both the NeXT and the DEC Multinational character sets include the
+   French OE digraph, but Latin-1 does not. Therefore French words
+   containing this character might not arrive intact when Latin-1 is the
+   transfer character-set, but will with UTF-8 or UCS-2, since the UCS
+   includes the OE digraph (but so does Latin-9).
+
+   UCS-2 should be chosen as a transfer character-set only for Japanese
+   text files that contain a large preponderance of Kanji, since in this
+   case (and only this case) UCS-2 (two bytes per Kanji) is more
+   efficient than UTF-8 (three bytes per Kanji). The same will be true
+   for Chinese and Korean when they are supported by Kermit. UCS-2 should
+   never be used as a transfer character-set with a transfer partner that
+   does not support UCS-2 since this can cause file corruption (see last
+   paragraph in this section).
+
+   Note that Kermit's repeat-count compression is 100% ineffective for
+   UCS-2, and is also ineffective for multibyte characters in UTF-8 and
+   EUC-JP; this is because repeat-compression is a transport-level
+   mechanism that operates on a per-byte basis; it has no knowledge of
+   the distinction between a byte and a character.
+
+   When C-Kermit starts, it sets up associations ([545]Section 6.5) for
+   incoming files whose transfer character sets are UCS-2 or UTF-8
+   appropriately for the platform so that the file character-set for the
+   incoming file is UCS-2 in Windows and UTF-8 elsewhere. Otherwise,
+   C-Kermit does not make any default associations for UCS-2 or UTF-8,
+   but of course you may add or change associations to suit your needs
+   and preferences by including the appropriate ASSOCIATE commands in
+   your Kermit startup file. For example, if you are a PC user and deal
+   only with text written in Greek and English, you can:
+
+  ASSOCIATE TRANSFER-CHARACTER-SET UTF8 CP869
+  ASSOCIATE TRANSFER-CHARACTER-SET UCS2 CP869
+  ASSOCIATE FILE-CHARACTER-SET CP869 UTF8
+
+   Note that when file transfer involves conversion between a single-byte
+   character set and UCS-2 or UTF-8, the file-transfer thermometer and
+   estimated time left might be inaccurate, since they are based on the
+   source file size, not the transfer encoding. This is purely a cosmetic
+   issue and does not effect the final result. (And is not, strictly
+   speaking, a bug; Kermit protocol presently includes no method for the
+   sender to furnish an "estimated transfer size" to the receiver, and in
+   any case any such guess could be as far off as the file size, given
+   the many other factors that come into play, such as compression and
+   prefixing).
+
+   A caution about FTP and UCS-2. As noted previously, if you transfer a
+   UCS-2 file with FTP in binary mode between two computers with opposite
+   Endianness, the result will have its bytes in the wrong order.
+   However, if you use FTP to transfer a UCS-2 file in "ascii" (text)
+   mode to ANY computer, even if it is identical to yours, the result
+   will be corrupted because FTP's line-terminator conversions do not
+   account for UCS-2. The same holds when sending from a UCS-aware Kermit
+   program to an older Kermit program in text mode with a transfer
+   character-set of UCS-2. So use UCS-2 as a transfer character-set ONLY
+   with a UCS-2-aware Kermit partner.
+     _________________________________________________________________
+
+    6.6.5.2. The TRANSLATE Command
+
+   In Kermit versions that have Unicode support included, TRANSLATE now
+   always goes through Unicode; that is, the source set is converted to
+   UCS-2 and thence to the target set. This is a major improvement, since
+   in prior releases, C-Kermit had to pick the "most appropriate"
+   transfer character-set as the intermediate set, and this would result
+   in the loss of any characters that the source and target sets had in
+   common but were lacking from the intermediate set (for example the OE
+   digraph when translating from NeXT to DEC MCS through Latin-1). This
+   never happens when Unicode is the intermediate set because Unicode is
+   a superset of all other character sets supported by Kermit. A more
+   dramatic example would be translation between Cyrillic PC code page
+   866 and KOI8-R ([546]Section 6.4); formerly all the line- and
+   box-drawing characters would be lost (since ISO 8859-5 does not have
+   any); now the ones that these two sets have in common are preserved.
+
+   UCS-2 and UTF-8 are now both supported as source-file and
+   destination-file character sets by C-Kermit's TRANSLATE command, for
+   example:
+
+  translate oofa.txt ucs2 latin1 oofa-l1.txt
+
+   translates oofa.txt from UCS-2 to Latin-1, storing the result as
+   oofa-l1.txt. Similarly:
+
+  translate oofa.txt utf8 latin1 oofa-l1.txt
+  translate oofa.txt latin1 ucs2 oofa-ucs2.txt
+  translate oofa.txt latin1 utf8 oofa-utf8.txt
+  translate oofa.txt ucs2 utf8 oofa-utf8.txt
+  translate oofa.txt utf8 ucs2 oofa-ucs2.txt
+
+   Treatment of the UCS-2 BOM is exactly the same as for file transfer.
+   Note that if a UCS-2 source file is in the "wrong" byte order and
+   lacks a BOM, and you don't tell Kermit about it with SET FILE UCS
+   BYTE-ORDER, the result of the translation is total gibberish. Recall
+   that you can use COPY /SWAP-BYTES to switch the byte order of an
+   errant UCS-2 file (or any other file for that matter, if you can think
+   of a reason to). Also note that:
+
+  translate oofa.txt ucs2 ucs2 new.txt
+
+   Produces a result in the native (or SET FILE UCS) byte-order as long
+   as oofa.txt has a BOM.
+
+   As a side benefit of the Unicode work, the TRANSLATE command now works
+   for the first time also for all Japanese character sets that Kermit
+   supports. In other words, if you have a Japanese text file in any of
+   the following encodings:
+
+  EUC-JP
+  Shift-JIS
+  JIS-7
+  UCS-2
+  UTF-8
+
+   You can use the TRANSLATE command to convert to any other encoding
+   from the same list.
+     _________________________________________________________________
+
+    6.6.5.3. Terminal Connection
+
+   The CONNECT command now allows UTF-8 as a local or remote terminal
+   character-set:
+
+  SET TERMINAL CHARACTER-SET { ..., UTF8 } { ..., UTF8 }
+  SET TERMINAL REMOTE-CHARACTER-SET { ..., UTF8 }
+  SET TERMINAL LOCAL-CHARACTER-SET { ..., UTF8 }
+
+   (Recall that Kermit's terminal character-set has two "ends" -- the set
+   used on the host to which Kermit is connected, and the set used on the
+   local keyboard and screen.)
+
+   UCS-2 is not supported as a terminal character-set (either end) since
+   (a) it is not used that way anywhere to our knowledge, and (b) the
+   problems of Endianness and the high likelihood of loss of
+   synchronization make it impractical. (Telecommunications is
+   byte-oriented; if one byte, or any odd number of bytes, is lost
+   because of buffer overruns, circuit resets, etc (or likewise if a
+   burst of noise appears that takes the guise of an odd number of
+   bytes), the byte order of the subsequent data stream will be
+   backwards; unlike UTF-8 and traditional byte-based character sets,
+   UCS-2 is not "self synchronizing".)
+
+   UTF-8 does not have byte-order or synchronization problems and is
+   growing in popularity as a terminal character set as well as in other
+   application areas. It allows a single terminal session to use multiple
+   scripts (Roman, Cyrillic, Greek, etc) without ISO 2022 character-set
+   switching (which terminal emulators like Kermit 95 can handle but few
+   host applications understand or use), and meshes nicely with the
+   Unicode screen fonts that are beginning to appear.
+
+   UTF-8 was first used in Plan 9 and soon will be available in Linux. It
+   will probably spread from there (Unicode in some form is, of course,
+   also used in Windows NT, but only internally -- not for access from
+   outside).
+
+   To use UTF-8 or any other character set that uses 8-bit bytes in your
+   terminal session, be sure to tell C-Kermit to:
+
+  SET TERMINAL BYTESIZE 8
+  SET COMMAND BYTESIZE 8
+  SET PARITY NONE
+
+   (or use the shortcut command, EIGHTBIT, which does all three at once).
+
+   In a setup where your local Kermit program uses a single-byte
+   character set such as PC Code Page 850 and the remote host uses UTF-8:
+
+  SET TERM CHAR UTF8 CP850
+
+   or:
+
+  SET TERM REMOTE CHAR UTF8
+  SET TERM LOCAL CHAR CP850
+
+   all works as expected. UTF-8 text on the remote displays correctly on
+   your screen, and when you type CP850 characters, they are translated
+   to UTF-8 sequences for transmission, and the echo from the host is
+   translated from UTF-8 back to CP850. Telnet negotiations and
+   autodownload take place before any character-set translation and work
+   as before. The session log (if text mode was selected for it) contains
+   only the local terminal character-set. And so on.
+
+   Kermit merely supplies translations from UTF-8 to your local terminal
+   character-set (this includes treating UTF-8 Line Separator and
+   Paragraph separator as CRLF). However, Kermit does does not, at
+   present, perform "canonicalization" of composed sequences, nor does it
+   automatically execute bidirectionality algorithms for display of
+   mixed-direction text (e.g. Hebrew and English). Such presentation
+   issues, like all others in the terminal-host regime, are left to the
+   host.
+
+   By the way, C-Kermit also allows UTF-8 to be the local end of the
+   terminal character-set, but so far this code is not tested, since we
+   don't have a UTF-8 console or terminal to work with. However, it can
+   be stated without doubt that C-Kermit's key mapping will not work for
+   UTF-8 values, since (a) the key map is indexed by 8-bit byte values
+   and (b) C-Kermit reads keystrokes a byte at a time (these comments do
+   not apply to K95, which has direct access to the keyboard and can read
+   "wide" keycodes and uses them to index a "wide" keymap).
+
+   Restrictions: As noted, the CONNECT command does not support UCS-2 as
+   a REMOTE TERMINAL character-set. Neither does it support the Japanese
+   sets EUC-JP, JIS-7, and Shift-JIS. Support for the Japanese sets (and
+   possibly Chinese and Korean too) might be added in a future release.
+   Since the TRANSMIT command (next section) uses the same REMOTE
+   TERMINAL character-sets as the CONNECT command, it has the same
+   restrictions.
+     _________________________________________________________________
+
+    6.6.5.4. The TRANSMIT Command
+
+   As described in Chapter 15 of [547]Using C-Kermit and [548]Section
+   4.21 of this document, the TRANSMIT command can be used to upload a
+   file without protocol, more or less as if you were typing it on your
+   keyboard while connected to the host. When TRANSMITting in text mode,
+   the file's character set is converted to the host's unless you have
+   SET TERMINAL CHARACTER-SET TRANSPARENT, or you include the new
+   TRANSMIT switch, /TRANSPARENT.
+
+   Before C-Kermit 7.0, the file character-set was assumed to be the same
+   as the local end of the terminal character-set, and the TRANSMIT
+   command used the same translations as the CONNECT command, ignoring
+   the file character-set.
+
+   In C-Kermit 7.0, that assumption (a poor one to begin with) can no
+   longer be made, since UCS-2 can be a file character-set but not a
+   terminal character-set. So now the file's character-set is given by
+   your most recent SET FILE CHARACTER-SET command. The host's character
+   set is the remote end of your most recent SET TERMINAL CHARACTER-SET
+   command:
+
+  SET TERMINAL CHARACTER-SET remote-set [ local-set ]
+
+   or:
+
+  SET TERMINAL REMOTE-CHARACTER-SET remote-set
+
+   The TRANSMIT command converts each source-file character from the FILE
+   character-set to the REMOTE TERMINAL character-set, and then transmits
+   the translated characters according to your SET TRANSMIT preferences
+   (Chapter 15).
+
+   If you have SET TRANSMIT ECHO ON, and the host is echoing the
+   transmitted characters, the echos are converted from the remote
+   terminal character-set to the local terminal character-set.
+
+  [ A picture would help... ]
+
+   Confused? Let's work through an example. Suppose your local computer
+   is a NeXTstation, on which text files are encoded in the NeXT
+   character set, and that the remote computer is a Data General AViiON,
+   which uses the Data General International character set. Further
+   suppose that you are logged in to the NeXT from a VT220 terminal which
+   uses the DEC Multinational character set.
+
+   You need to convert the file from NeXT encoding to DG encoding and
+   convert the echoes from DG encoding to DEC encoding. So on the NeXT,
+   tell C-Kermit to:
+
+  eightbit
+  set file character-set next
+  set term character-set dg-international dec-mcs
+  transmit /text nextdata.txt
+
+   (This assumes you have some sort of collection process already set up
+   on the Data General, such as a text editor or the venerable "cat >
+   foo". The EIGHTBIT command is equivalent to SET TERMINAL BYTESIZE 8,
+   SET COMMAND BYTESIZE 8, SET PARITY NONE.)
+
+   To further complicate matters, suppose your local terminal character
+   set is the same as the remote one, so you don't need terminal
+   character-set translation, but you need to TRANSMIT a file that is in
+   a different character set and you want it translated to the host set.
+   In this case, use SET TERM CHARACTER-SET to actually specify the
+   character set used on each end, rather than specifying TRANSPARENT:
+
+  eightbit
+  set file character-set ucs2
+  set term character-set latin1 latin1
+  transmit /text ucs2data.txt
+
+   The distinction between:
+
+  SET TERMINAL CHARACTER-SET xxx yyy
+
+   (where xxx and yyy are the same set) and:
+
+  SET TERMINAL CHARACTER-SET TRANSPARENT
+
+   is new to C-Kermit 7.0, but affects only the TRANSMIT command.
+
+   The TRANSMIT command currently does nothing special with UCS-2/UTF-8
+   Line and Paragraph Separator characters; more experience is required
+   to find out how these behave in a genuine Unicode terminal-host
+   setting.
+
+   Restrictions: As noted, the TRANSMIT command translates from the FILE
+   character-set to the REMOTE TERMINAL character-set. This rules out
+   translations to any character set that is not supported as a REMOTE
+   TERMINAL character-set, such as UCS-2, EUC-JP, JIS-7, and Shift-JIS.
+     _________________________________________________________________
+
+    6.6.5.5. Summary of Kermit Unicode Commands
+
+   Specifying file character-set and byte order:
+          SET FILE CHARACTER-SET { ..., UCS2, UTF8 }
+          REMOTE SET FILE CHARACTER-SET { ..., UCS2, UTF8 } (See next
+          section)
+          SET FILE UCS BOM { ON, OFF }
+          SET FILE UCS BYTE-ORDER { BIG-ENDIAN, LITTLE-ENDIAN }
+
+   Specifying the transfer character-set:
+          SET TRANSFER CHARACTER-SET { ..., UCS-2, UTF-8 }
+          REMOTE SET TRANSFER CHARACTER-SET { ..., UCS-2, UTF-8 }
+
+   Specifying the terminal character-set:
+          SET TERMINAL CHARACTER-SET { ..., UTF8 } { ..., UTF8 }
+          SET TERMINAL REMOTE-CHARACTER-SET { ..., UTF8 }
+          SET TERMINAL LOCAL-CHARACTER-SET { ..., UTF8 }
+
+   Displaying settings:
+          SHOW FILE
+          SHOW TRANSFER
+          SHOW TERMINAL
+          SHOW CHARACTER-SETS
+
+   Commands that use these settings include:
+          SEND, RECEIVE, GET, etc.
+          CONNECT
+          TRANSMIT
+          LOG SESSION
+
+   Converting files:
+          TRANSLATE infile { ..., UCS-2, UTF-8 } { ..., UCS-2, UTF-8 }
+          outfile
+          COPY /SWAP-BYTES infile outfile
+     _________________________________________________________________
+
+  6.7. Client/Server Character-Set Switching
+
+   A simple mechanism has been added to allow the client to change the
+   server's FILE CHARACTER-SET:
+
+   REMOTE SET FILE CHARACTER-SET name
+          The client asks the server to change its file character-set to
+          the one given. The name must match one of the server's file
+          character-set names. For convenience, C-Kermit uses its own
+          file character-set keyword list for parsing this command so you
+          can use ? for help and Tab or Esc for completion. However,
+          since the server might have a different repertoire (or even use
+          different names for the same sets), C-Kermit accepts any string
+          you supply and sends it to the server. The server, if it
+          supports this command (C-Kermit 7.0 and K95 1.1.19 do), sets
+          its file character-set as requested, and also disables
+          automatic character-set switching ([549]Section 6.5). If the
+          server does not support this command or if it does not support
+          the given character set, the REMOTE SET FILE CHARACTER-SET
+          command fails.
+
+   Here's an example that sends a Japanese text file encoded in Shift-JIS
+   to a server using every combination of Kermit's Japanese-capable file
+   and transfer character sets:
+
+  dcl \&x[] = euc ucs2 utf8             ; transfer character-sets
+  dcl \&y[] = eu uc ut                  ; 2-letter abbreviations for them
+  dcl \&f[] = shift euc jis7 ucs2 utf8  ; file character-sets
+  dcl \&g[] = sj eu j7 uc ut            ; 2-letter abbreviations
+
+  set file char shift-jis               ; local file character-set is Shift-JIS
+  for \%i 1 \fdim(&x) 1 {               ; for each transfer character-set...
+      set xfer char \&x[\%i]            ; set it
+      for \%j 1 \fdim(&f) 1 {           ; for each remote file character-set...
+          remote set file char \&f[\%j] ; set it
+          if fail exit 1 SERVER REJECTED CHARSET
+          send /text meibo-sj.html meibo-sj-\&y[\%i]-\&g[\%j].txt ; send the fi
+le
+          if fail exit 1 TRANSFER FAILED
+      }
+  }
+
+   The Kermit-370 server does not support REMOTE SET FILE CHARACTER-SET,
+   but since it supports REMOTE KERMIT commands, you can get the same
+   effect with REMOTE KERMIT SET FILE CHARACTER-SET name.
+     _________________________________________________________________
+
+  7. SCRIPT PROGRAMMING
+
+   (Also see [550]Section 2.8, Scripting Local Programs.)
+
+  7.0. Bug Fixes
+
+   The following script programming bugs were fixed in C-Kermit 7.0:
+
+     * IF EXIST and IF DIRECTORY were fixed to properly strip braces from
+       around their arguments, so "if directory {C:\Program Files}", etc,
+       would work as expected. However, this means that if the file or
+       directory name is actually enclosed in braces, the braces must be
+       doubled.
+     * The READ command did not fail if the READ file wasn't open; now it
+       does.
+     * The READ command refused to read the last or only line of a file
+       if it did not end with a proper line terminator; now it does.
+     * The END command, when given from within a SWITCH statement, did
+       not exit from the current macro or command file; instead it just
+       terminated the SWITCH.
+     _________________________________________________________________
+
+  7.1. The INPUT Command
+
+   7.1.1. INPUT Timeouts
+
+   The description of the INPUT command on page 422 fails to mention the
+   following two points about the timeout (which apply to C-Kermit 6.0
+   and later):
+
+    1. "INPUT -1 text" (or "INPUT \%x text", where \%x is any variable
+       whose value is -1 or less) means "wait forever". This form of the
+       INPUT command fails only if it is interrupted, since it will never
+       time out.
+    2. INPUT 0 performs a nonblocking read of material that has already
+       arrived but has not yet been read, and succeeds immediately if the
+       target string is found, or fails immediately if it is not found.
+
+   The same points apply to MINPUT. REINPUT ignores its timeout
+   parameter.
+     _________________________________________________________________
+
+    7.1.2. New INPUT Controls
+
+   The following new INPUT controls were added in version 7.0:
+
+   SET INPUT AUTODOWNLOAD { ON, OFF }
+          Explained in [551]Section 7.7.
+
+   SET INPUT CANCELLATION { ON, OFF }
+          This governs whether an INPUT command can be canceled by
+          "pressing any key" on the keyboard. Normally it can be, in
+          which case the INPUT command fails immediately and \v(instatus)
+          is set to 2, indicating interruption. SET INPUT CANCELLATION
+          OFF disables keyboard cancellations; thus if the search text is
+          not encountered, the INPUT command will run for its entire
+          timeout interval. SET INPUT CANCELLATION OFF does not disable
+          interruption by Ctrl-C, however; every command needs an
+          emergency exit. (If you really want to disable interruption by
+          Ctrl-C, use SET COMMAND INTERRUPTION OFF.)
+
+   Also see [552]Section 7.2 for any new variables related to INPUT.
+     _________________________________________________________________
+
+    7.1.3. INPUT with Pattern Matching
+
+   C-Kermit 7.0 allows INPUT, MINPUT, and REINPUT targets to be a pattern
+   (explained in [553]Sections 1.19 and [554]4.9). This solves a
+   long-standing problem illustrated by the following scenario: a certain
+   company has a bank of TCP/IP modem servers, with hostnames server1,
+   server2, server3, and so on. Each server's prompt is its name,
+   followed by a colon (:), for example "Server72:". Without INPUT
+   patterns, it would be rather difficult to wait for the prompt. The
+   brute force approach:
+
+  minput 20 Server1: Server2: Server3: ... (enumerating each one)
+
+   is subject to failure whenever a new server is added. A more subtle
+   approach:
+
+  input 20 Server
+  if fail ...
+  input 2 :
+
+   is liable to false positives, e.g. "Welcome to the XYZ Corp Modem
+   Server. Please read the following message:"...
+
+   With patterns, you can match the prompt with "Server*:" (which doesn't
+   solve the "false positives" problem, but certainly is more compact
+   than the brute force method), or with more specific patterns such as
+   "Server[1-9]:" and "Server[1-9][0-9]:", or equivalently:
+
+  Server{[1-9],[1-9][0-9]}:
+
+   meaning the word "Server" followed by a single digit (1-9) or by two
+   digits representing a number from 1 to 99, followed by a colon.
+
+   INPUT pattern matching has been added in a way that does not interfere
+   with existing scripts. No new commands or switches are used. The
+   simple rule is: if an INPUT search target is the argument of the (new)
+   \fpattern() function, it is a pattern. Otherwise it is taken
+   literally, as before. For example:
+
+  input 5 a*b
+
+   searches for an 'a' followed by an asterisk ('*'), followed by a 'b'.
+   But:
+
+  input 5 \fpattern(a*b)
+
+   searches for an 'a' followed by anything at all up to and including
+   the first 'b'. This means that any search target to INPUT, MINPUT, or
+   REINPUT can be a pattern or a literal string, and in particular that
+   MINPUT can accommodate any mixture of patterns and literal strings.
+
+   In selecting patterns, note that:
+
+     * A leading '*' is always implied so there is no need to include
+       one.
+     * A trailing '*' is meaningless and ignored.
+     * A '*' by itself matches the first character that arrives.
+
+   A syntax note: If your pattern is a selection list, meaning a list of
+   alternatives separated by commas and enclosed in braces, then the
+   outer braces will be stripped by various levels of parsers, so you
+   must include three of each:
+
+  input 10 \fpattern({{{abc,mno,xyz}}})
+
+   Note that this is equivalent to:
+
+  minput 10 abc mno xyz
+
+   except for the setting of the \v(minput) variable.
+
+   And a caution: INPUT pattern matching has a limitation that you
+   probably never noticed with literal-string matching, namely that there
+   is a limit on the size of the match. For example, if the pattern is
+   "a*b", the match will succeed if the 'a' and 'b' are not separated by
+   more than (say) 8K bytes, but will fail if they are farther apart than
+   that. In such cases, it better to use two INPUTs (e.g. "input 10 a"
+   and then "input 100 b").
+     _________________________________________________________________
+
+    7.1.4. The INPUT Match Result
+
+   The result of any INPUT, MINPUT, or REINPUT command, no matter whether
+   the search targets are patterns or literal strings, is available in
+   the new \v(inmatch) variable. For example:
+
+  minput 10 cat \fpattern([dh]og)
+  if success echo MINPUT matched "\v(inmatch)"
+
+   This is especially useful when a pattern was matched, since it makes
+   the string that matched the pattern available to Kermit; there would
+   be no way to get it otherwise.
+
+   After an INPUT command, you can view all the INPUT-related variables
+   by typing "show variables in" (abbreviate as "sho var in"), which
+   shows the values of all built-in variables whose names start with
+   "in".
+     _________________________________________________________________
+
+  7.2. New or Improved Built-In Variables
+
+   \v(blockcheck)
+          Current BLOCK-CHECK setting, 1, 2, 3, or 4. 4 is the code for
+          BLANK-FREE-2.
+
+   \v(byteorder)
+          The machine's byte order: 0 = Big Endian, 1 = Little Endian.
+
+   \v(cmdbufsize)
+          The length of the command buffer, which is the maximum size for
+          a macro, a command, a variable, or anything else in C-Kermit's
+          script language.
+
+   \v(ctty)
+          The device name of C-Kermit's controlling (login) terminal.
+
+   \v(filename)
+          Described in [555]Sections 4.1 and [556]4.2.
+
+   \v(filenumber)
+          Described in [557]Sections 4.1 and [558]4.2.
+
+   \v(filespec)
+          As of C-Kermit 7.0, contains fully qualified filenames rather
+          than (usually) relative ones.
+
+   \v(return)
+          Now holds the END n value of the macro that most recently
+          returned, in case END was used rather than RETURN.
+
+   \v(editor)
+          Pathname of preferred text editor
+
+   \v(editopts)
+          Command-line options for editor
+
+   \v(editfile)
+          File most recently edited
+
+   \v(browser)
+          Pathname of preferred Web browser
+
+   \v(browsopts)
+          Command-line options for Web browser
+
+   \v(browsurl)
+          URL most recently given to Web browser
+
+   \v(dialtype)
+          Type of call most recently placed (see [559]Section 2.1.11).
+
+   \v(kbchar)
+          The character, if any, that was typed at the keyboard to to
+          interrupt the most recent PAUSE, SLEEP, WAIT, MSLEEP, or INPUT
+          command; empty if the most recent such command was not
+          interrupted from the keyboard.
+
+   \v(lockdir)
+          UNIX only - The name of the UUCP lockfile directory, if known,
+          otherwise "(unknown)".
+
+   \v(lockpid)
+          UNIX only - PID of process that owns the communication port
+          that you tried to open with a SET LINE command that failed
+          because the port was in use, otherwise empty. This variable is
+          set with every SET LINE command.
+
+   \v(cx_time)
+          If no connection (SET HOST, SET LINE, DIAL, TELNET, etc) is
+          active, this is 0. If a connection is active, this is the
+          number of seconds since the connection was made.
+
+   \v(hwparity)
+          If hardware parity is in effect, this variable gives its value,
+          such as "even" or "odd" (in which case, the \v(parity) variable
+          will be "none"). Otherwise this variable is empty.
+
+   \v(serial)
+          Current serial port settings in 8N1 format ([560]Section 2.10).
+
+   \v(errno)
+          In UNIX, the current value of the C runtime errno variable,
+          which is quite volatile (meaning that often an "interesting"
+          error code can be overwritten by some other library call or
+          system service that sets errno before you have a chance to look
+          at it). In VMS, the error code returned by the system or
+          library call that most recently failed (success codes are not
+          saved). Not available in other operating systems.
+
+   \v(errstring)
+          The UNIX or VMS system error message that corresponds to
+          \v(errno). Not available in all OS's. Also see
+          [561]\ferrstring().
+
+   \v(setlinemsg)
+          The error message, if any, from the most recent SET LINE, SET
+          PORT, SET HOST, TELNET, or other connection-making command.
+          This is not necessarily the same as \v(errstring) since these
+          commands might fail without generating a system error code, for
+          example (in UNIX) because a lockfile existed indicating the
+          device was assigned by another user.
+
+   \v(exitstatus)
+          The exit status C-Kermit would return if it exited now.
+
+   \v(pexitstat)
+          The exit status of the inferior process most recently invoked
+          by C-Kermit (by RUN, !, REDIRECT, SEND /COMMAND, etc). In VMS,
+          this code can be given to \ferrstring() to get the
+          corresponding error message (in UNIX, program/command return
+          codes are not the same as system error codes). Not available in
+          operating systems other than UNIX and VMS. See [562]Section
+          4.2.5 for details.
+
+   \v(inmatch)
+          The incoming string of characters, if any, that matched the
+          most recent INPUT, REINPUT, or MINPUT command.
+
+   \v(intime)
+          The number of milliseconds (thousandths of seconds) it took for
+          the most recent INPUT command to find its match, or -1 if no
+          INPUT command has been given yet. If the INPUT command timed
+          out, the value is approximately equal to 1000 times the INPUT
+          timeout. If INPUT failed for some other reason, the value is
+          undefined (\v(instatus) gives INPUT completion status). If your
+          version of C-Kermit is built without high-precision
+          floating-point timers, this number will always be a multiple of
+          1000.
+
+   \v(inwait)
+          The number of seconds specified as the timeout in the most
+          recent INPUT command.
+
+   \v(dialsuffix)
+          Dialing suffix for use during PDIAL sequence; see [563]Section
+          2.1.10.
+
+   \v(pid)
+          UNIX, VMS, and K95 only. C-Kermit's primary process ID,
+          numeric, decimal. If you want to show it in hex, use
+          \fn2hex(\v(pid)) If you want to show it in octal, use
+          \fn2octal(\v(pid)).
+
+   \v(printer)
+          Current printer name or SET PRINTER value.
+
+   \v(p_ctl)
+          Control prefix char \v(p_8bit) 8-bit prefix char (if parity not
+          none)
+
+   \v(p_rpt)
+          Repeat prefix char (if repeat compression enabled)
+
+   \v(herald)
+          Kermit's version herald
+
+   \v(test)
+          Kermit's test version, if any, or 0 if this is not a test
+          version. Typical values for test versions are "Alpha.03" or
+          "Beta.14".
+
+   \v(sendlist)
+          The number of entries in the SEND-LIST, 0 if none. Note:
+          entries do not necessarily correspond to files, since an entry
+          might contain wildcards. Also note that the value does not go
+          back to 0 after the files in the list are sent. To reset this
+          variable, use CLEAR SEND-LIST. The purpose of this variable is
+          to determine if a SEND command, when given without any
+          filenames, will be legal. Example:
+
+  xif \v(sendlist) { send } else { send oofa.txt }
+
+   \v(trigger)
+          If the most recent CONNECT session was terminated automatically
+          by a trigger, this variable contains the trigger value.
+
+   \v(ty_ln)
+          TYPE line number (during TYPE)
+
+   \v(ty_lc)
+          TYPE line count (after TYPE)
+
+   \v(ty_mc)
+          TYPE match count (after TYPE)
+
+   \v(xferstat)
+          Status of most recent file transfer:
+
+-1: No transfer yet
+ 0: Succeeded
+ 1: Failed
+
+   \v(xfermsg)
+          If the most recent file transfer failed, this is the reason. If
+          it succeeded, \v(xfermsg) is an empty string.
+
+   \v(tftime)
+          Total elapsed time of most recent file transfer operation, in
+          seconds.
+
+   \v(textdir)
+          Directory that holds (or is supposed to hold) Kermit text files
+          such as installation instructions, release notes, update notes,
+          read-me files, "beware" files, etc.
+
+   \v(name)
+          The name with which the Kermit program was invoked, e.g.
+          "kermit", "wermit", "k95", "k2", etc (see [564]Section 9.1).
+
+   \v(osname)
+          Name of operating system on computer where C-Kermit is running,
+          obtained at runtime (from uname or equivalent).
+
+   \v(osversion)
+          Version of operating system on computer where C-Kermit is
+          running, obtained at runtime (from uname or equivalent).
+
+   \v(osrelease)
+          Release of operating system on computer where C-Kermit is
+          running, obtained at runtime (from uname or equivalent).
+
+   \v(model)
+          The specific hardware model of the computer where C-Kermit is
+          running, if known.
+
+   \v(math_pi)
+          The value of Pi (see [565]Section 7.23)
+
+   \v(math_e)
+          The value of e (see [566]Section 7.23)
+
+   \v(math_precision)
+          How many significant digits in a floating-point number.
+
+   \v(f_count)
+          Result of the most recent FILE COUNT (FCOUNT) command.
+
+   \v(f_error)
+          Numeric error code of most recent FILE command.
+
+   \v(f_max)
+          Maximum number of files open simultaneously.
+
+   The math constants are given in the precision of underlying computer's
+   floating-point arithmetic.
+
+   Note the distinction between \v(osname), \v(osversion), and
+   \v(platform); the latter refers to the platform for which and/or upon
+   which C-Kermit was built, as opposed to the one on which it is
+   actually running. Also note that each operating system can, and
+   probably will, interpret and fill in the os* variables differently, or
+   not at all.
+
+   The SHOW VARIABLES command now accepts a variable name, prefix, or
+   pattern:
+
+  show variables         Shows all variables.
+  show variables t       Shows all variables that start with "t".
+  show variables *ver*   Shows all variables whose names contain "ver".
+  show variables *ver    Ditto (an implied "*" is appended).
+     _________________________________________________________________
+
+  7.3. New or Improved Built-In Functions
+
+   The following new file-i/o functions are explained in [567]Section
+   1.22.
+
+  \f_status(channel)           Status of file open on channel
+  \f_pos(channel)              Read/write (byte) pointer of given file
+  \f_line(channel)             Current line of file
+  \f_handle(channel)           Handle of file
+  \f_eof(channel)              Whether given file is at EOF
+  \f_getchar(channel)          Read a char from given file
+  \f_getline(channel)          Read a line from given file
+  \f_getblock(channel,n)       Read a block from given file
+  \f_putchar(channel,c)        Write a char to given file
+  \f_putline(channel,string)   Write a line to given file
+  \f_putblock(channel,string)  Write a block to given file
+
+   The following new date-time-related functions are explained in
+   [568]Section 1.6:
+
+  \fday()                Returns day of week of given date
+  \fnday()               Returns numeric day of week of given date
+  \ftime()               Returns time portion of given date-time
+  \fntime()              Converts time to seconds since midnight
+  \fn2time()             Converts seconds since midnight to hh:mm:ss
+  \fcvtdate(date-time)   Converts free-format date to yyyymmdd hh:mm:ss
+  \fdayofyear(date-time) Converts date to yyyyddd (day-of-year) format
+  \fdoy(date-time)       Synonym for \fdayofyear()
+  \fdoy2date(dayofyear)  Converts yyyyddd to yyyymmdd
+  \fmjd(date-time)       Converts free-format date to Modified Julian Date
+  \fmjd2date(mjd)        Converts modified Julian date to yyyymmdd
+
+   The new floating-point arithmetic functions are explained in
+   [569]Section 7.23. f1 and f2 are floating-point (real) numbers; d is
+   the number of decimal places to show:
+
+  \ffpabsolute(f1,d)     Absolute value of f1
+  \ffpadd(f1,f2,d)       f1 + f1
+  \ffpcosine(f1,d)       Cosine of f1
+  \ffpdivide(f1,f2,d)    f1 divided by f2
+  \ffpexp(f1,d)          e to the f1 power
+  \ffpint(f1)            Integer part of f1
+  \ffplog10(f1,d)        Log base 10 of f1
+  \ffplogn(f1,d)         Natural log of f1
+  \ffpmaximum(f1,f2,d)   Maximum of f1 and f2
+  \ffpminimum(f1,f2,d)   Minimum of f1 and f2
+  \ffpmodulus(f1,f2,d)   Modulus of f1 and f2
+  \ffpmultiply(f1,f2,d)  Product of f1 and f2
+  \ffpraise(f1,f2,d)     Raise f1 to power f2
+  \ffpround(f1,d)        Round f1 to d places
+  \ffpsine(f1,d)         Sine of f1
+  \ffpsqrt(f1,d)         Square root of f1
+  \ffpsubtract(f1,f2,d)  f2 - f1
+  \ffptangent(f1,d)      Tangent of f1
+
+   Integer number functions:
+
+   \fabsolute(n)
+          Absolute value of integer n.
+
+   \frandom(n)
+          Returns a random integer between 0 and n-1.
+
+   \fradix(s,n1,n2)
+          If the string s is an integer in radix n1, the result is the
+          same number expressed in radix n2, where n1 and n2 may be any
+          number from 2 through 36, expressed as decimal numbers, or
+          variables (etc) that evaluate to decimal numbers. For the
+          source and result, the digits of any radix, r, are the first r
+          characters in the sequence 0-9,a-z (case doesn't matter for the
+          letters). The string s may have a sign, + or -; if it starts
+          with a minus (-) sign, the result also has a minus sign.
+
+   The \fradix() function does not work with floating-point numbers. It
+   does not reveal the internal storage format of a number; for example,
+   \fradix(-1,10,16) is -1, not something like FFFFFFFFFF. If all three
+   arguments are not given, or if n1 or n2 are not numbers between 2 and
+   36 inclusive, or s is not a number in radix n1, an error occurs and
+   the empty string is returned. \fradix() also does not offer
+   extended-precision arithmetic; number values are limited to those
+   expressed as a long integer in the architecture of the underlying
+   computer, usually 32 or 64 bits. If you give it an argument whose
+   absolute value is larger than can be held in an unsigned long, the
+   result is -1.
+
+   The next four are shorthand functions for decimal/hexadecimal and
+   decimal/octal number conversion:
+
+   \fn2hex(n)
+          Returns the hexadecimal (base 16) representation of the integer
+          n. This is different from \fhexify(s), which treats its
+          argument as a string rather than a number. The result is always
+          left-padded with 0's to make its length even. Examples:
+
+  \n2hex(0)   = "00"                    \fhexify(0)   = "30"
+  \n2hex(255) = "ff"                    \fhexify(255) = "323535"
+  \n2hex(256) = "0100"                  \fhexify(256) = "323536"
+
+   \fhex2n(x)
+          Converts hexadecimal number x to decimal equivalent decimal
+          number. This is the inverse of \fn2hex(). Equivalent to
+          \fradix(s,16,10).
+
+   \fn2octal(n)
+          Returns the octal (base 8) representation of the number n.
+          Examples:
+
+  \n2octal(0) = "0"
+  \n2oct(255) = "377"
+  \n2oct(256) = "400"
+  Equivalent to \fradix(n,10,8).
+
+   \foct2n(n)
+          Returns the decimal representation of the given octal number,
+          n. The inverse of \fn2octal(). Equivalent to \fradix(n,8,10).
+
+   String functions:
+
+   \s(name[n:m])
+          Equivalent to \fsubstring(\m(name),n,m) ([570]Section 7.24).
+
+   \:(name[n:m])
+          Equivalent to \fsubstring(name,n,m) (where "name" is any
+          \-quantity) ([571]Section 7.24).
+
+   \fleft(s,n)
+          The leftmost ncharacters of string s; equivalent to
+          \fsubstring(s,1,n).
+
+   \fstripx(string,char)
+          Returns the part of the string up to the rightmost occurrence,
+          if any, of the given character. The default character is period
+          (.) Examples:
+
+  \fstripx(foo/bar,/)                 = "foo"
+  \fstripx(foo/bar/baz,/)             = "foo/bar"
+  \fstripx(autoexec.bat,.)            = "autoexec"
+  \fstripx(autoexec.bat)              = "autoexec"
+  \fstripx(fstripx(foo/bar/baz,/),/)  = "foo"
+
+   \flop(string,character)
+          Returns the portion of the string starting after the first
+          occurrence of the given character. The default character is
+          period (.) Examples:
+
+  \flop(autoexec.bat)                 = "bat"
+  \flop(baz.foo/bar)                  = "foo/bar"
+  \flop(baz.foo/bar,/)                = "bar
+
+   \fstripn(string,n)
+          Returns the string with ncharacters removed from the end.
+          Example:
+
+  \fstripn(12345678,3)                = "12345"
+
+          (For more discussion of \fstripx(), \fstripn(), and \flop() see
+          [572]Section 4.2.3).
+
+   \fb64encode(s)
+          Returns the Base-64 encoding of the string s.
+
+   \fb64decode(s)
+          Returns the decoding of the Base-64 string s. Fails if s is not
+          a Base-64 string, or if its length is not a multiple of 4. Note
+          that if any of the result bytes are null (0), the result string
+          stops there. There is no way to represent strings that contain
+          null bytes in C-Kermit (the same is true for \funhexify()).
+
+   \fword(s1,n,s2,s3)
+          Extracts word number nfrom string s1. By default, a "word" is
+          any sequence of ASCII letters or digits; nis 1-based. If nis
+          omitted, "1" is used. Examples:
+
+  \fword(one two three)    = "one"
+  \fword(one two three,1)  = "one"
+  \fword(one two three,2)  = "two"
+  \fword(one two three,3)  = "three"
+
+          and:
+
+    \fword(\v(dialresult),2) = "31200"
+
+          is "31200" if \v(dialresult) is (e.g.) "CONNECT
+          31200/ARQ/V32/LAPM/V42BIS".
+
+          If you include s2, this replaces the default break set. For
+          example, suppose you have a string \%a whose value is:
+
+  $150.00 $300.00 $39.95
+
+          and you want each dollar amount to be a word; use:
+
+  \fword(\%a,\%n,{ })
+
+          This returns dollar amount number \%n, e.g. "$300.00" for \%n =
+          2. "{ }" denotes a space (you must enclose it in braces,
+          otherwise it is squeezed out). Note that ASCII control
+          characters are always included in the break set; you don't have
+          to specify them (and you can't not specify them).
+
+          The optional s3 argument lists characters (even control
+          characters) that normally would be considered separators that
+          you want included in words. So the dollars-and-cents example
+          could also be handled this way:
+
+  \fword(\%a,\%n,,$.)
+
+          in other words, use the default separator list, but remove "$"
+          and "." from it so they will be considered part of a word.
+
+   \fsplit(s1,&a,s2,s3)
+          This is like \fword(), except instead of extracting and
+          returning a particular word from string s1, it counts the words
+          and optionally assigns them to the array whose identifying
+          letter, a-z, is given after the "&" in the second argument,
+          with the first word going into element 1, the second into
+          element 2, and so on. The rules regarding break and include
+          lists (s2 and s3) are exactly the same as for \fword().
+          \fsplit() returns the number of words that were assigned, which
+          is either the number of words in the string, or the dimension
+          of the array, whichever is less. If the array is not declared,
+          \fsplit() creates it and returns a number which is both the
+          number of words in s1 and the dimension of the new array.
+          Examples:
+
+  declare \&w[20]        ; (Optional.)
+  ...
+  read \%s               ; \%s is "This is a sentence with seven words."
+  ...
+  echo "\fsplit(\%s)"    ; This would print "7".
+  echo "\fsplit(\%s,&w)" ; Ditto, and also assigns them to array \&w[].
+
+  echo "\&w[7]"          ; This would print "words".
+
+          If the line contained fields that were delimited by colon (:),
+          you would use \fsplit(\%s,&w,:). If the fields were delimited
+          by comma, then you would use \fsplit(\%s,&w,{,}); in this case
+          the literal comma must be enclosed in braces to distinguish it
+          from the comma that separates function arguments. To get a word
+          count without loading an array, but still specify break and/or
+          include lists, leave the array argument empty:
+
+   echo "\fsplit(\%s,,:)" ; Use colon as the separator.
+
+          WARNINGS:
+
+         1. If you use the same array repeatedly, \fsplit() leaves any
+            trailing members undisturbed. For example:
+  dcl \&w[10]
+  \fsplit(1 2 3 4 5,&w) ; Sets \&w[1] thru \&w[5].
+  \fsplit(a b c,&w)     ; Sets \&w[1]-[3] leaving [4]-[5] as they were.
+         2. If you allow \fsplit to create the array (by not declaring it
+            first), it is dimensioned to the number of elements it was
+            created with:
+  \fsplit(1 2 3,&x)     ; Creates an array \&x[] with 3 elements.
+  \fsplit(a b c d e,&x) ; This overflows the array.
+
+          Thus if you want to use \fsplit() repeatedly on the same array,
+          either dimension it in advance to the maximum expected size
+          (and then some -- more efficient), or else destroy it after
+          each use (to allow for unexpectedly large arguments). Example
+          using a dynamic array:
+
+  fopen /read \%c some-file
+  if fail ...
+  set function error on    ; See [573]Section 7.12
+  while true {
+      dcl \&w[]            ; Destroy \&[w] each time thru the loop
+      fread /line \%c \%a
+      if fail break
+      asg \%x \fsplit(\%a,&w)
+      if fail ...
+      ; (do what you want with \&w[] here...)
+  }
+  fclose \%c
+
+   \frindex(s1,s2,n)
+          The "n" argument to \frindex() now works consistently (in
+          mirror image) with the corresponding \findex() argument. In
+          each case, the (n-1)-most characters of s2 are ignored in the
+          search; for findex, this means the starting position of the
+          search is n (the default nis 1, and 0 is treated like 1). For
+          \frindex() it means the default starting point is:
+
+  length(s2) - length(s1) - n (with the same defaults for n).
+
+   \fsearch(pattern,string[,position])
+          Exactly like \findex(), except with a pattern (see [574]Section
+          7.9) rather than a literal string.
+
+   \frsearch(pattern,string[,position])
+          Exactly like \frindex(), except with a pattern rather than a
+          literal string.
+
+          File Functions:
+
+   \ffiles(), \fnextfile()
+          It is no longer necessary to copy the file list to an array
+          before use, as shown on p.398 of [575]Using C-Kermit 2nd
+          Edition. \ffiles() and friends now make their own safe copies
+          of the file list. Thus constructions like the following are now
+          possible:
+
+  for \%i 1 \ffiles(*.txt) 1 { send \fnextfile() }
+
+          The same is true for the new function \frfiles(),
+          \fdirectories(), and \frdirectories(), described in
+          [576]Section 4.11.3.
+
+          But note that each reference to \fnextfile() still gets you the
+          next file. So "if newer \fnextfile() foo.txt send \fnextfile()"
+          compares one file's age with that of foo.txt, and then sends an
+          entirely different file. If you're going to refer to the same
+          file more than once, assign it to a variable:
+
+  asg \%f \fnextfile()
+  if newer \%f foo.txt send \%f
+
+          (note: assign, not define).
+
+          Also note that \ffiles(), \frfiles(), \fdirectories(), and
+          \frdirectories() all now accept on optional 2nd argument: the
+          name of an array to load with the resulting file or directory
+          list, explained in [577]Section 4.11.3. So you can also load an
+          array with the filelist when you need to refer to the same file
+          more than once:
+
+  for \%i 1 \ffiles(*,&a) 1 { if newer \&a[\%i] foo.txt send \&a[\%i] }
+
+   \fpermissions(file)
+          Returns the platform-specific permissions string for the file,
+          such as "-rw-rw-r--" in UNIX or "(RWE,RWE,RE,E)" in VMS.
+
+   \fdirname(f)
+          Given a file specification f, this function returns the
+          complete pathname of directory the file is in.
+
+   Array Functions:
+
+   \fdimension(&a)
+          Returns the dimension declared for the array whose identifying
+          letter, a-z, or special character "_" or "@", is given after
+          the "&" in the argument. If the array is not declared, 0 is
+          returned. Note that when used with the macro argument vector
+          array, \&_[] (see [578]Section 7.5), the value of this function
+          is one less than \v(argc), and when used with the C-Kermit
+          command-line argument vector array, \&@[], it is equal to the
+          \v(args) variable. Examples:
+
+  echo \fdimension(&a)       ; Not declared.
+  0
+  declare \&a[12]            ; Now it's declared.
+  echo \fdim(&a)
+  12
+
+   \farraylook(pattern,arrayname)
+          Looks in the given array for the pattern and returns the index
+          of the first element that matches, if any, or -1 if none match.
+          The arrayname can include a range specifier to restrict to
+          search to a segment of the array, e.g.
+          \farraylook(*xyz*,&a[32:63]). For greater detail see
+          [579]Section 7.10.7.
+
+   \ftablelook(keyword,arrayname[,delimiter])
+          Looks in the given "table", which must be sorted, for the given
+          keyword. Returns the index of the table element that uniquely
+          matches the given keyword, or -1 if none match, or -2 if more
+          than 1 match. For greater detail see [580]Section 7.10.7.
+
+   Other new functions:
+
+   \fip2hex(s)
+          Converts a dotted decimal IP address to an 8-digit hexadecimal
+          number. \fip2hex(128.59.39.2) = 803b2702.
+
+   \fhex2ip(x)
+          Converts an 8-digit hexadecimal IP address to dotted decimal
+          form, e.g. \fhex2ip(803b2702) = 128.59.39.2. The inverse of
+          \fip2hex().
+
+   \fcommand()
+   \frawcommand()
+          These run an external command and return its output; see
+          [581]Section 4.2.8.4.
+
+   \fdialconvert(s)
+          s is a phone number in either literal or portable format (not a
+          dialing directory entry name). The function returns the dial
+          string that would actually be used when dialing from the
+          current location (after processing country code, area code, and
+          other SET DIAL values).
+
+   \ferrstring(n)
+          Returns the system error message associated with the (numeric)
+          error code n. UNIX and VMS only. Use in conjunction with
+          \v(errno) or \v(pexitstat). See [582]Section 4.2.5 for a usage
+          example. Note: This function doesn't work in Windows because
+          there is not a consistent error-code-to-message mapping; error
+          code "x" means something completely different depending on
+          whether it comes from the C runtime library, Winsock, a
+          Windows-32 API, TAPI, etc,
+
+   \fpattern(s)
+          Used in INPUT, REINPUT, and MINPUT commands to denote search
+          strings that are to be treated as patterns rather than
+          literally.
+
+   Also see [583]Section 7.8 on built-in help for functions.
+     _________________________________________________________________
+
+  7.4. New IF Conditions
+
+   IF AVAILABLE feature command
+          Executes the command if the given feature is available.
+          Presently used only to determine if specific authentication and
+          encryption options are available. Type "if available ?" to see
+          which features may be tested.
+
+   IF FLOAT f1 command
+          Executes command if f1 is a legal floating point number (which
+          includes integers). Use this to preverify arguments for the
+          \ffp...() floating-point arithmetic functions, e.g. "if float
+          \%1 echo \ffpint(\%1)".
+
+   IF == n1 n2 command
+          Synonym for "if =" (numeric equality). Note that as of C-Kermit
+          7.0, this and all other numeric comparison operators also work
+          for floating-point numbers.
+
+   IF != n1 n2 command
+          Executes the command if n1 and n2 are both numbers or variables
+          containing numbers and the value of n1 is not equal to the
+          value of n2. This is equivalent to "if not = n1 n2".
+
+   IF <= n1 n2 command
+          Executes the command if n1 and n2 are both numbers or variables
+          containing numbers and the value of n1 is less than or equal to
+          the value of n2. This is equivalent to "if not > n1 n2".
+
+   IF >= n1 n2 command
+          Executes the command if n1 and n2 are both numbers or variables
+          containing numbers and the value of n1 is greater than or equal
+          to the value of n2. Equivalent to "if not < n1 n2".
+
+   IF COMMAND word command
+          Executes the command if word is a built-in C-Kermit command.
+          Example:
+
+  if not command copy define { copy run copy \%1 \%2 }".
+
+          This defines a COPY macro that runs an external COPY command if
+          COPY is not already a built-in command.
+
+   IF LOCAL command
+          Executes the command if Kermit is in local mode, i.e. if it has
+          a SET LINE, SET PORT, or SET HOST (TELNET, RLOGIN, etc) device
+          or connection open. Does not execute the command if in remote
+          mode.
+
+   IF MATCH string pattern command
+          Executes the command if the string matches the pattern. For a
+          description of the syntax for the pattern, see [584]Section
+          4.9.1. If you want to test if the string contains pattern, use
+          IF \fsearch(pattern,string).
+
+   IF OPEN { DEBUG-LOG, SESSION-LOG, TRANSACTION-LOG, ... } command
+          Executes the command if the given file is open, fails if it is
+          not open. Type IF OPEN ? for a complete list of files that can
+          be checked (all the files that can be opened with the OPEN or
+          LOG commands).
+
+   IF QUIET command
+          Executes the command if SET QUIET is ON, and does not execute
+          it if SET QUIET is OFF. Example: IF NOT QUIET ECHO { This is a
+          message.}.
+
+   IF READABLE name
+          Succeeds if name is the name of an existing file or directory
+          that is readable.
+
+   IF WRITEABLE name
+          Succeeds if name is the name of an existing file or directory
+          that is writeable, e.g.:
+
+  if not writeable \v(lockdir) echo Please read installation instructions!
+
+   IF FLAG command
+          This tests a user-settable condition, which can mean anything
+          you like. SET FLAG ON causes subsequent IF FLAG commands to
+          succeed; SET FLAG OFF causes them to fail. One way to use it
+          would be for debugging your scripts; precede any debugging
+          statements with IF FLAG. Then SET FLAG on to debug your script,
+          SET FLAG OFF to run it without debugging. Another common use is
+          for causing an inner loop to cause an outer loop to exit.
+
+   IF C-KERMIT command
+          C-Kermit, but not Kermit 95 or MS-DOS Kermit, executes the
+          command.
+
+   IF K-95 command
+          Kermit 95, but not C-Kermit or MS-DOS Kermit, executes the
+          command.
+
+   IF MS-KERMIT command
+          MS-DOS Kermit, but not C-Kermit or Kermit 95, executes the
+          command.
+     _________________________________________________________________
+
+  7.5. Using More than Ten Macro Arguments
+
+   The \v(argc) variable now gives the actual number of arguments, even
+   if the number is greater than 9:
+
+  C-Kermit> define xx echo \v(argc)
+  C-Kermit> xx 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
+  27
+
+   Remember that \v(argc) includes the name of the macro itself, so it is
+   always at least 1, and is always 1 greater than the actual number of
+   arguments. As in versions 6.0 and earlier, if more than 9 arguments
+   are given, only the first nine are assigned to the variables \%1..\%9.
+
+   The \&_[] array, discussed on page 353 of [585]Using C-Kermit, 2nd ed,
+   now holds all the arguments, up to some implementation-dependent limit
+   (64 or greater), rather than only the first 9. To illustrate: the
+   following macro tells the number of arguments it was called with and
+   then prints them:
+
+  define show_all_args {
+      local \%i
+      echo \&_[0] - Number of arguments: \feval(\v(argc)-1)
+      for \%i 1 \v(argc)-1 1 { echo \flpad(\%i,3). "\&_[\%i]" }
+  }
+
+   Within a macro \&_[0], like \%0, contains the name of the macro.
+
+   At top level, the \&_[] array is filled as follows:
+
+     * If the first argument on the C-Kermit command line was a filename,
+       or C-Kermit was invoked from a "Kerbang" script ([586]Section
+       7.19), element 0 contains the filename, and elements 1 through
+       \v(argc)-1 hold the remaining command-line arguments.
+     * Otherwise the program name goes in element 0, and elements 1
+       through \v(argc)-1 hold any arguments that were included after
+       "--" or "="
+
+   The new \%* variable, when used within a macro, is replaced by the
+   text that followed the macro name in the macro invocation. If no
+   arguments were given, \%* is replaced by the empty string. Examples:
+
+  C-Kermit> define xx echo [\%*]
+  C-Kermit> define \%a oofa
+  C-Kermit> xx
+  []
+  C-Kermit> xx \%a
+  [oofa]
+  C-Kermit> xx a
+  [a]
+  C-Kermit> xx a b
+  [a b]
+  C-Kermit> xx a b c
+  [a b c]
+  C-Kermit> xx 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]
+
+   Note that \%* can not be used at top level, since Kermit does not have
+   access to the raw command line (only to its elements separately, after
+   they have been processed by the shell and the C library).
+
+   C-Kermit 7.0 also adds a SHIFT command:
+
+   SHIFT [ number ]
+          Shifts the macro arguments (except argument 0) the given number
+          of places to the left and adjusts \v(argc) accordingly. The
+          default number is 1.
+
+   To illustrate, suppose macro XXX is invoked as follows:
+
+  xxx arg1 arg2 arg3
+
+   Then inside XXX, \%1 is "arg1", \%2 is "arg2", and \%3 is "arg3".
+   After a SHIFT command is given inside XXX, then \%1 is "arg2", \%2 is
+   "arg3", and \%3 is empty. \%0 (the name of the macro) remains
+   unchanged.
+
+   If more than 9 arguments were given, then arguments are shifted into
+   the \%1..9 variables from the argument vector array.
+
+   At top level, the SHIFT command operates on the \&_[] array and \%1..9
+   variables; the \&@[] array is not affected. See [587]Section 7.16 for
+   details.
+
+   The \%* variable is not affected by the SHIFT command.
+     _________________________________________________________________
+
+  7.6. Clarification of Function Call Syntax
+
+   Spaces are normally stripped from the front and back of each function
+   argument; to prevent this enclose the argument in braces:
+
+  \fsplit(\%a,&a,{ })
+
+   However, function calls that contain spaces can make trouble when the
+   function is to be used in a "word" field, since space separates words.
+   For example:
+
+  for \%i 1 \fsplit(\%a,&a,{ }) 1 {
+    echo \%i. "\&a[\%i]"
+  }
+
+   In most cases, the trouble can be averted by enclosing the function
+   reference in braces:
+
+  for \%i 1 {\fsplit(\%a,&a,{ })} 1 {
+    echo \%i. "\&a[\%i]"
+  }
+
+   or by replacing spaces with \32 (the ASCII code for space):
+
+  for \%i 1 \fsplit(\%a,&a,\32) 1 {
+    echo \%i. "\&a[\%i]"
+  }
+
+   Braces are also used in function calls to indicate grouping. For
+   example:
+
+  \fsubstring(abcd,2,2) = "bc"
+
+   But suppose "abcd" needed to contain a comma:
+
+  \fsubstring(ab,cd,2,2)
+
+   This would cause an error, since "cd" appears to be the second
+   argument, when really you want the first "2" to be the second
+   argument. Braces to the rescue:
+
+  \fsubstring({ab,cd},2,2) = "b,"
+
+   Similarly, leading and trailing spaces are stripped from each
+   argument, so:
+
+  \fsubstring( abcd ,2,2) = "bc"
+
+   but braces preserve them:
+
+  \fsubstring({ abcd },2,2) = "ab"
+
+   Given these special uses for braces, there is no way to pass literal
+   braces to the function itself. For example:
+
+  \fsubstring(ab{cd,2,2)
+
+   causes an error.
+
+   So if you need a function to include braces, define a variable
+   containing the string that has braces. Example:
+
+  define \%a ab{cd
+  \fsubstring(\%a,2,2) = "b{"
+
+   If the string is to start with a leading brace and end with a closing
+   brace, then double braces must appear around the string (which itself
+   is enclosed in braces):
+
+  define \%a {{{foo}}}
+  \fsubstring(\%a) = "{foo}"
+
+   This also works for any other kind of string:
+
+  define \%a {{ab{cd}}
+  echo \fsubstring(\%a) = "ab{cd"
+     _________________________________________________________________
+
+  7.7. Autodownload during INPUT Command Execution
+
+   As of 6.1 / 1.1.12, C-Kermit can be told to look for incoming Kermit
+   (or Zmodem) packets during execution of an INPUT command. By default
+   (for consistency with earlier releases), this is not done. You can
+   enable this feature with:
+
+  SET INPUT AUTODOWNLOAD ON
+
+   (and disable it again with OFF.)
+
+   One possible use for this feature is as a server mode with a time
+   limit:
+
+  INPUT 3600 secret-string-to-end-the-INPUT-command
+
+   In this example, any GET, SEND, or REMOTE commands received within one
+   hour (3600 seconds) of when the INPUT command was issued will be
+   executed. Here's another example, in which we want to stay open until
+   11:30pm, or until interrupted by seven consecutive Ctrl-C (\3)
+   characters:
+
+  INPUT 23:30:00 \3\3\3\3\3\3\3
+
+   The INPUT AUTODOWNLOAD setting is displayed by SHOW SCRIPTS or SHOW
+   INPUT.
+     _________________________________________________________________
+
+  7.8. Built-in Help for Functions.
+
+   Beginning in C-Kermit 7.0, you may obtain a description of the calling
+   conventions and return values of any built-in function, such as
+   \fsubstring(), with the new HELP FUNCTION command; give the function's
+   name without the leading "\f", e.g. "help func substring". You can use
+   ?, completion, and abbreviation in the normal manner.
+     _________________________________________________________________
+
+  7.9. Variable Assignments
+
+    7.9.1. Assignment Operators
+
+   Programmers accustomed to languages such as C or Fortran might find
+   Kermit's method of assigning values to variables unnatural or awkward.
+   Beginning in C-Kermit 7.0, you can use the following alternative
+   notation:
+
+ .name = value    is equivalent to   DEFINE name value
+ .name := value   is equivalent to   ASSIGN name value
+ .name ::= value  is equivalent to   ASSIGN name \feval(value)
+
+   When the command begins with a period (.), this indicates an
+   assignment. The name can be a macro name, a \%{digit,letter} variable,
+   or an array element. There can be space(s) between "." and the name.
+   Examples:
+
+  .\%a = This is a string  ; Same as "define \%a This is a string"
+  echo \%a
+  This is a string
+
+  .xxx = \%a               ; Same as "define xxx \%a"
+  echo \m(xxx)
+  \%a
+
+  .xxx := \%a              ; Same as "assign xxx \%a"
+  echo \m(xxx)
+  This is a string
+
+  declare \&a[2]           ; Use with arrays...
+  define \%i 2
+  .\&a[1] = first
+  .\&a[\%i] = second
+
+   The following sequence illustrates the differences among three levels
+   of evaluation:
+
+  .\%x = 2          ; Define a variable to have a numeric value
+  .\%y = (3 + \%x)  ; Define another variable as an arithmetic expression
+
+  .xxx = 4 * \%y    ; "=" simply copies the right-hand side.
+  echo \m(xxx)
+  4 * \%y
+
+  .xxx := 4 * \%y   ; ":=" evaluates the variables first, then copies.
+  echo \m(xxx)
+  4 * (3 + 2)
+
+  .xxx ::= 4 * \%y  ; "::=" evaluates the expression, then copies.
+  echo \m(xxx)
+  20
+
+   You can also use this syntax to clear (undefine) a variable:
+
+  .\%a = oofa       ; Define the variable
+  echo "\%a"
+  "oofa"
+  .\%a              ; Clear the variable
+  echo "\%a"
+  ""
+
+   Extra credit: Can you guess what happens below when the file "abc"
+   does not exist?
+
+  fopen /read \%c abc
+  if fail ...
+     _________________________________________________________________
+
+    7.9.2. New Assignment Commands
+
+   Recall the DEFINE and ASSIGN commands, and their hidden counterparts,
+   _DEFINE and _ASSIGN. The former take the variable name literally, the
+   latter evaluate the variable-name field to form the variable name
+   dynamically. Examples:
+
+  DEFINE \%x foo    ; Sets the value of the variable \%x to "foo".
+  DEFINE \%a \%x    ; Sets the value of the variable \%a to "\%x".
+  _DEFINE x_\%a \%x ; Sets the value of the variable x_foo to "\%x".
+  ASSIGN \%a \%x    ; Sets the value of the variable \%a to the "foo".
+  _ASSIGN x_\%a \%x ; Sets the value of the variable x_foo to "foo".
+
+   This concept has been carried over to the remaining
+   variable-assignment commands: EVALUATE, INCREMENT, and DECREMENT:
+
+   EVALUATE variablename expression
+          Evaluates the arithmetic expression and assigns its value to
+          the variable whose name is given. Example: "eval \%a 1+1"
+          assigns "2" to \%a.
+
+   _EVALUATE metaname expression
+          Evaluates the arithmetic expression and assigns its value to
+          the variable whose name is computed from the given metaname.
+          Example: "eval foo<\%a>::\%1 \%2 * (\%3 + \%4)" assigns the
+          value of "\%2 * (\%3 + \%4)" to the variable whose name is
+          computed from "foo<\%a>::\%1".
+
+   INCREMENT variablename [ expression ]
+          Evaluates the arithmetic expression and adds its value to the
+          value of the variable whose name is given. Example: "increment
+          \%a".
+
+   _INCREMENT metaname [ expression ]
+          Evaluates the arithmetic expression and adds its value to the
+          value of the variable whose name is computed from the given
+          metaname. Example: "_increment Words::\%1.count[\%2]".
+
+   DECREMENT variablename [ expression ]
+          Evaluates the arithmetic expression and subtracts its value
+          from the value of the variable whose name is given.
+
+   _DECREMENT metaname [ expression ]
+          Evaluates the arithmetic expression and subtracts its value
+          from the value of the variable whose name is computed from the
+          given metaname.
+
+   WARNING: The syntax of the EVALUATE command has changed since C-Kermit
+   6.0 and K95 1.1.17. Previously, it did not include a variable name,
+   only an expression. To restore the old behavior, use SET EVALUATE OLD.
+   To return to the new behavior after restoring the old behavior, use
+   SET EVALUATE NEW.
+
+   NOTE: There are no analogs to the "_" commands for the operators
+   described in [588]Section 7.9.1; those operators can not be used to
+   assign values to variables whose names must be computed.
+     _________________________________________________________________
+
+  7.10. Arrays
+
+   C-Kermit 7.0 adds lots of new array-related features, and groups them
+   together under the NEW ARRAY command:
+
+   ARRAY { CLEAR, COPY, DECLARE, DESTROY, RESIZE, SHOW, SORT }
+
+   In each of the ARRAY commands, wherever an array name is expected,
+   "short forms" may be used. For example, all of the following are
+   acceptable:
+
+  array show \&a[]  (or SHOW ARRAY...)
+  array show &a[]
+  array show a[]
+  array show &a
+  array show a
+
+   In addition, ranges are accepted in the ARRAY COPY, ARRAY CLEAR, ARRAY
+   SET, ARRAY SHOW, and ARRAY SORT commands:
+
+  array clear \&a[16]     ; Clears 16 thru end
+  array clear &a[16]      ; Ditto
+  array clear a[16]       ; Ditto
+
+  array clear \&a[16:32]  ; Clears 16 thru 32
+  array clear &a[16:32]   ; Ditto
+  array clear a[16:32]    ; Ditto
+
+   When using array names as function arguments, you must omit the "\"
+   and you must include the "&". You may optionally include empty
+   brackets. Examples:
+
+  \fsplit(\%a,a)          ; Bad
+  \fsplit(\%a,\&a)        ; Bad
+  \fsplit(\%a,&a[3])      ; Bad
+
+  \fsplit(\%a,&a)         ; Good
+  \fsplit(\%a,&a[])       ; Good
+     _________________________________________________________________
+
+    7.10.1. Array Initializers
+
+   Beginning in C-Kermit 7.0, you may initialize an array -- in whole or
+   in part -- in its declaration:
+
+   [ ARRAY ] DECLARE array-name[size] [ = ] [ value1 [ value2 [...] ] ]
+
+   For compatibility with versions 5A and 6.0, the ARRAY keyword is
+   optional. DECLARE can also be spelled DCL.
+
+   Initializers are (a) optional, (b) start with element 1, (c) must be
+   enclosed in braces if they contain spaces, and (d) are evaluated
+   according to normal rules by the DECLARE command prior to assignment.
+   Thus the assignments made here are the same as those made by the
+   ASSIGN command. This allows you to initialize array elements from the
+   values of other variables. If you actually want to initialize an array
+   element to variable's name, as opposed to its value, use double
+   backslashes (as in "\\&a", "\\v(time)", etc).
+
+   The size (dimension) of the array is optional. If the size is omitted,
+   as in "\&a[]", then the array sizes itself to the number of
+   initializers; if there are no initializers the array is not declared
+   or, if it was declared previously, it is destroyed. If a size is
+   given, any extra elements in the initialization list are discarded and
+   ignored.
+
+   NOTE: Unlike in C, the list of initializers is NOT enclosed in braces.
+   Instead, braces are used to group multiple words together. So:
+
+  ARRAY DECLARE \&a[] = { one two three }
+
+   would create an array with two elements (0 and 1), with element 1
+   having the value " one two three ".
+
+   Examples:
+
+   ARRAY DECLARE \&a[16]
+          Declares the array \&a with 17 elements (0 through 16), in
+          which all elements are initially empty. If the array \&a[]
+          existed before, the earlier copy is destroyed.
+
+   ARRAY DECLARE &a[16]
+   ARRAY DECLARE a[16]
+   ARRAY DCL \&a[16]
+   ARRAY DCL &a[16]
+   ARRAY DCL a[16]
+   DECLARE \&a[16]
+   DECLARE &a[16]
+   DECLARE a[16]
+   DCL \&a[16]
+   DCL &a[16]
+   DCL a[16]
+          All of the above are the same as the first example.
+
+   ARRAY DECLARE \&a[16] = alpha beta {gamma delta}
+          Declares the array \&a with 17 elements (0 through 16),
+          initializing \&a[1] to "alpha", \&a[2] to "beta", and \&a[3] to
+          "gamma delta". The remaining elements are empty.
+
+   ARRAY DECLARE \&a[] = alpha beta {gamma delta}
+          Same as the previous example, but the array is automatically
+          dimensioned to 3.
+
+   ARRAY DECLARE \&a[3] = alpha beta {gamma delta} epsilon zeta
+          Too many initializers; only the first three are kept.
+
+   ARRAY DECLARE \&a[0]
+   ARRAY DECLARE \&a[]
+   ARRAY DECLARE &a[]
+   ARRAY DECLARE &a
+   ARRAY DECLARE a
+   DECLARE \&[0]
+   DECLARE a
+   DCL a
+          All of these are equivalent. Each destroys \&a[] if it exists.
+          Declaring an array with a dimension of 0 is the same as ARRAY
+          DESTROY arrayname.
+
+   ARRAY DECLARE \&a[] = \%1 \%2 \%3
+          Declares the array \&a with 3 elements (0 through 3),
+          initializing \&a[1] to the value of \%1, \&a[2] to the value of
+          \%2, and \&a[3] to the value of \%3. In this case, any
+          reference to one of these array elements is replaced by the
+          value of the corresponding \%n variable at the time the
+          declaration was executed (immediate evaluation; the array
+          element's value does not change if the initializer variable's
+          value changes).
+
+   ARRAY DECLARE \&a[] = \\%1 \\%2 \\%3
+          Declares the array \&a with 3 elements (0 through 3),
+          initializing \&a[1] to the string "\%1", \&a[2] to "\%2", and
+          \&a[3] to "\%3". In this case any reference to one of these
+          array elements is replaced by the CURRENT value of the
+          corresponding \%n variable (deferred evaluation -- the array
+          element's value follows the value of the initializer variable).
+
+   The equal sign (=) preceding the initializer list is optional, but is
+   recommended for clarity. If you need to initialize element 1 to a
+   literal equal sign, use two of them, separated by a space, as in this
+   example:
+
+  ARRAY DECLARE \&a[] = = + - * /
+
+   Remember, element 0 is not initialized by the DECLARE command. To
+   initialize element 0, use a regular DEFINE or ASSIGN command:
+
+  ARRAY DECLARE \&a[] one two three four five six seven eight nine
+  DEFINE \&a[0] zero
+
+   Finally, remember that every command level has its own local array,
+   \&_[], containing all the macro arguments (\%0, \%1, ...) for that
+   level. See [589]Section 7.5 for details.
+     _________________________________________________________________
+
+    7.10.2. Turning a String into an Array of Words
+
+   The \fsplit(s1,&a,s2,s3) function assigns the words of string s1 to
+   successive elements of the array (beginning with element 1) whose
+   identifying letter, a-z, is given after the "&" in the second
+   argument, using break and include characters given in s2 and s3. See
+   [590]Section 7.3 for details.
+     _________________________________________________________________
+
+    7.10.3. Arrays of Filenames
+
+   See [591]Section 4.11.3 for news about how \ffiles() and related
+   functions can assign a list of filenames to an array. To recapitulate
+   briefly here:
+
+  \ffiles(*,&a)
+
+   assigns all files that match the first argument to the array denoted
+   by the second argument. If the array has not been declared, it is
+   declared automatically, with exactly the number of elements needed to
+   hold the file list; if it was previously declared, it is destroyed and
+   reused. The filenames are assigned starting at array element 1.
+   Element 0 holds the number of files in the list.
+
+   The DIRECTORY command ([592]Section 4.5.1) can also create filename
+   arrays if you give it the /ARRAY: switch; this allows selection
+   criteria beyond whether the filename matches the given pattern.
+
+   All functions and commands that create filename arrays store the
+   number of filenames, n, as element 0 of the array, and the filenames
+   as elements 1 through n.
+     _________________________________________________________________
+
+    7.10.4. Automatic Arrays
+
+   In a command file or macro, you can now have local (automatic) arrays.
+   Just give the name followed by empty subscript brackets (no spaces
+   inside the brackets please) in a LOCAL command, and then declare the
+   array:
+
+  LOCAL \%a \&a[] oofa
+  ARRAY DECLARE \&a[32] = value1 value2 value3 ...
+
+   This declares the scalar variable \%a, the array \&a[], and the macro
+   name "oofa" to be local, and then declares the new local copy of \&a[]
+   with 32 elements, perhaps assigning some initial values. When C-Kermit
+   exits from the command file or macro containing these command, the
+   previous \&a[] array is restored (and if there was no \&a[] at any
+   higher level, this will still be true). The process can be repeated to
+   any level. Thus it is now safe to write scripts or macros containing
+   arrays without danger of interfering with global arrays of the same
+   name.
+
+   Just as scalars are inherited by lower command levels, so are arrays.
+   So, for example, if \&a[] is declared at top level, all lower levels
+   will see it unless they include a "local \&a[]" statement, in which
+   case all levels at and beneath the level where the LOCAL statement was
+   executed will see the local copy. This too can be repeated to any
+   level.
+
+   On the other hand, if you DECLARE an array at a lower command level
+   without also making it LOCAL, this replaces the copy that was declared
+   at the lowest command level above this one.
+     _________________________________________________________________
+
+    7.10.5. Sorting Arrays
+
+   Although arrays can be sorted using FOR loops as shown on page 383 of
+   Using C-Kermit, 2nd Ed., this involves quite a bit of repetitive
+   interpretation by the command parser, and so can be slow for large
+   arrays. For this reason, C-Kermit 7.0 adds a built-in SORT command:
+
+   ARRAY SORT [ switches ] array [ array2 ]
+          Sorts the given array in place. Sorting is strictly lexical
+          (string based). The array name can be given fully, e.g.
+          "\&a[]", or the "\" and/or "&" and/or brackets can be omitted,
+          e.g. "array sort \&a[]", "sort &a", "sort a". Also, a range can
+          be indicated in the brackets as noted in [593]Section 7.10, to
+          restrict the sort to a range of elements (equivalent to the
+          /RANGE switch, described just below), e.g. "array sort
+          &a[20:30]".
+
+   A second array may be specified. If it is, and if it is at least as
+   big as the first array, it is sorted according to the first array. For
+   a sample application, see [594]Section 7.10.10.
+
+   See [595]Section 1.5 for an explanation of switches. The optional
+   switches are:
+
+   /CASE:{ON,OFF}
+          /CASE:ON means that alphabetic case is significant in
+          comparisons; uppercase letters are sorted before lowercase
+          ones. /CASE:OFF means case is ignored, e.g. "A" is the same as
+          "a". If this switch is not given, sorting is according the
+          current SET CASE setting.
+
+   /KEY:n
+          Comparison begins at position n(1-based) in each string. If no
+          key is given, the entire strings are compared. Only one key can
+          be given. If an array element is shorter than the key value, n,
+          that element is considered empty for comparison purposes, and
+          therefore lexically less than any element at least ncharacters
+          long.
+
+   /NUMERIC
+          If this switch is included, it means sorting should be numeric,
+          rather than lexical. The sort key is the string starting at the
+          key position, skipping any leading blanks or tabs, and then as
+          much of the string from that point on that fits the definition
+          of "numeric", terminating at the first character that does not
+          qualify. A numeric string has an optional sign (+ or -)
+          followed by one or more digits, and (if your version of Kermit
+          was built with floating-point support; see [596]Section 7.23 )
+          zero or one decimal point (period). If both /CASE and /NUMERIC
+          are given, /NUMERIC takes precedence.
+
+   /RANGE:n[:m]
+          Sort elements nthrough m of the array. By default, the entire
+          array from element 1 to its dimensioned size is sorted, which
+          might produce surprising results if the array is not full; see
+          example in [597]Section 7.10.7. If ":m" is omitted from the
+          range, the dimensioned size is used. Thus, to sort an entire
+          array, \&a[], including its 0th element, use "sort /range:0
+          &a". You can also sort any desired section of an array, e.g.
+          "sort /range:10:20 &a" or "sort /range:\%i:\%j-1 &b". As noted
+          above, you can also specify a range in the array-name brackets.
+          If you specify a range in the array-name brackets AND with a
+          /RANGE switch, the ones in the brackets take precedence.
+
+   /REVERSE
+          Sort in reverse order. If this switch is not given, the array
+          is sorted in ascending order.
+
+   Remember that numeric switch arguments can be numbers, arithmetic
+   expressions, or variables whose values are numbers or expressions, as
+   illustrated in the /RANGE examples above.
+
+   A typical sorting application might be to list students' test scores
+   in descending order. Suppose you had the following records:
+
+  olaf      65
+  olga      98
+  ivan      83
+  xena     100
+
+   (and so on) stored in array \&s[] (e.g. by reading them from a file as
+   illustrated in [598]section 7.10.7). In these records, the student's
+   name is in columns 1-9 and the score in 10-12. So to rearrange the
+   list in descending order of score:
+
+  sort /key:10 /reverse &s
+
+   Then to list your top five students:
+
+  for \%i 1 5 1 { echo \&s[\%i] }
+
+   Or more simply (see next section):
+
+  show array a[1:5]
+
+   To illustrate the difference between a lexical and a numeric sort,
+   suppose you have the following records (the lines that are numbered,
+   starting at column 1) in array \&a[]:
+
+    Column   1         2
+    12345678901234567890
+
+   1. Ivan 10.0 2. Olaf 9.95 3. Olga 101.5
+
+   ARRAY SORT /KEY:10 &a[] would order them 3,1,2, but ARRAY SORT /KEY:10
+   /NUMERIC &a[] would order them 2,1,3.
+     _________________________________________________________________
+
+    7.10.6. Displaying Arrays
+
+   The SHOW ARRAY command (or ARRAY SHOW) now accepts an optional
+   array-name argument:
+
+  SHOW ARRAY \&a[]
+
+   (you can leave off the \, the \&, and/or the []'s if you like; "show
+   array a" is equivalent to "show array \&a[]"). When an array is
+   specified, its dimension is shown and all defined (non-empty) elements
+   are listed.
+
+   Example:
+
+  assign \%n \ffiles(*,&a)  ; Fill an array with filenames ([599]Section 4.11.3
+)
+  show array \&a[]          ; Show the array we just read
+  array show \&a[]          ; Same as previous
+  array sort \&a[]          ; Sort the array
+  array show \&a[]          ; Show it after sorting
+  array show \&a            ; Show it again
+  array show &a             ; Show it again
+  array show a              ; Show it again
+
+   (The final four commands demonstrate the alternative forms that are
+   accepted for the array name.)
+
+   If you SHOW ARRAY without giving an array name, all defined arrays are
+   listed by name and dimension, but their contents are not shown.
+
+   You can also show a piece of an array by including a subscript or
+   range within the array brackets:
+
+  array show \&a[5]         ; Shows \&a[5]
+  array show &a[3:8]        ; Shows \&a[3] through \&a[8]
+  array show a[:\%n-1]      ; Shows \&a[0] through \&a[\%n-1]
+     _________________________________________________________________
+
+    7.10.7. Other Array Operations
+
+   ARRAY DESTROY arrayname
+          Destroys and undeclares the named array. Subscripts or ranges
+          are not accepted in this command.
+
+   ARRAY COPY array1 array2
+          Copies the first array to the second array. If the target array
+          has not been declared, it is created automatically with the
+          same size as the first. If it has been declared, it will be
+          used as declared; if the source array is larger, only as much
+          of it as will fit is copied to the target array. Syntax for
+          array1 and array2 is as in ARRAY SHOW (SHOW ARRAY). Example:
+
+  .\%n := \ffiles(*,&a)  ; Create and load array A with a file list.
+  array copy &a &b       ; Copy array A to array B.
+
+          The ARRAY COPY command also lets you copy pieces of arrays by
+          including range specifiers, as in these examples:
+
+        ARRAY COPY \&a[4:27] \&b
+                This copies \&a[] elements 4-27 to \&b[] elements 1-23,
+                creating \&b[] if necessary or, if \&b[] is already
+                declared, stopping early if its size is less than 23.
+
+        ARRAY COPY \&a[4:27] \&b[12]
+                This copies \&a[] elements 4-27 to \&b[] elements 12-35,
+                creating \&b[] if necessary or, if \&b[] is already
+                declared, stopping early if its size is less than 35.
+
+        ARRAY COPY \&a[4:27] \&b[12:14]
+                This copies \&a[] elements 4-6 to \&b[] elements 12-14,
+                creating \&b[] if necessary or, if \&b[] is already
+                declared, stopping early if its size is less than 14.
+
+        ARRAY COPY \&a[17] \&b
+                This copies all the elements of \&a[] starting with 17
+                until the last to \&b[], creating \&b[] if necessary or,
+                if \&b[] is already declared, stopping early if \&b[] is
+                not big enough.
+
+   ARRAY CLEAR arrayname
+          Sets all the elements of the array to the empty value. You may
+          also include a range specifier to clear only a selected portion
+          of the array; for example "array clear \&a[37:214]". If the
+          range is out of bounds, only the part of the array that is in
+          bounds is cleared.
+
+   ARRAY SET arrayname [ value ]
+          Sets all the elements of the array to the given value. If no
+          value is given, the array is cleared. You may also include a
+          range specifier to set only a selected portion of the array;
+          for example "array set \&a[1:9] -1". If the range is out of
+          bounds, only the part of the array that is in bounds is set.
+
+   ARRAY RESIZE arrayname size
+          Resizes the given array. If the size is greater than the
+          array's current dimension, new empty elements are added to the
+          end. If the size is less than the current dimension, the extra
+          elements are discarded. Note: If you have stored the array size
+          in element 0, ARRAY RESIZE does not change this value.
+          Alternative notation: ARRAY RESIZE arrayname[size]. For a
+          practical example, see [600]Section 7.10.11.
+
+   \farraylook(pattern,arrayname)
+          This function returns the index of the first element of the
+          given array that matches the given pattern (for details about
+          pattern syntax, see [601]section 4.9). The array name can
+          include a range specification to restrict the search to a given
+          segment of the array. If no elements match the pattern, -1 is
+          returned.
+
+   \ftablelook(keyword,arrayname[,delimiter])
+          Looks in the given "table", which must be sorted, for the given
+          keyword. The keyword need not be spelled out in full.
+          Pattern-matching characters should not be included as part of
+          the keyword. The function returns the index of the table
+          element that uniquely matches the given keyword, or -1 if none
+          match, or -2 if more than 1 match.
+
+   A "table" is an array that is sorted in lexical order; each of its
+   elements may contain multiple fields, delimited by the given delimiter
+   character or, if no delimiter is specified, a colon (:).
+
+   The \farraylook() function does exactly what you tell it. If you give
+   it a pattern that does not include wildcard characters (such as *, ?,
+   etc), it requires an exact match. For example:
+
+  \farraylook(oofa,&a)
+
+   searches for the first element of \&a[] whose value is "oofa". But:
+
+  \farraylook(oofa*,&a)
+
+   finds the first element whose value starts with "oofa", and;
+
+  \farraylook(*oofa,&a)
+
+   finds the first element whose value ends with "oofa", and;
+
+  \farraylook(*oofa*,&a)
+
+   finds the first element whose value contains "oofa".
+
+   Here's a simple demonstration of looking up patterns in arrays:
+
+  local \&a[] \%x \%n
+  declare \&a[] = zero one two three four five six seven eight nine ten
+  while true {
+      .\%x = 1
+      .\%n = 0
+      ask \%a { Pattern? }
+      if not def \%a exit 0 Done.
+      while <= \%x \fdim(&a) {
+          .\%x := \farraylook(\%a,&a[\%x])
+          if ( < \%x 0 ) break
+          echo \flpad(\%x,3). \&a[\%x]
+          increment \%x
+          increment \%n
+      }
+      if ( < \%n 1 ) echo Pattern not found - "\%a"
+  }
+
+   The array need not be sorted. When a pattern is given, a search is
+   performed; if there is a match, the matching element's index and the
+   element itself are printed, and the search begins again at the next
+   element. Thus each matching element is printed. If none match, the
+   "Pattern not found" message is printed. The process repeats for as
+   many patterns as the user wants to type, and terminates when the user
+   types an empty pattern.
+
+   Now let's build a little command parser, consisting of a keyword
+   table, and a loop to look up the user's commands in it with
+   \ftablelook(). In this case the array elements have "fields" separated
+   by colon (:) -- a keyword and a value. Keyword tables must be sorted
+   if \tablelook() is to work right, so after declaring and initializing
+   the table array, we sort it.
+
+  local \&k[] \%a \%i \%n
+
+  array declare \&k[] = drive:9 do:8 discuss:7 live:6 spend:5 help:4 quit:0
+
+  array sort &k                             ; Make sure array is sorted
+  echo Type "help" for help.                ; Print greeting & instructions
+
+  while true {                              ; Loop to get commands
+      undefine \%a
+      while not defined \%a {               ; Get a command
+          ask \%a { Command? }
+      }
+      .\%n := \ftablelook(\%a,&k)           ; Look up the command
+      switch \%n {                          ; Handle errors
+        :-1, echo Not found - "\%a"         ; Doesn't match
+             continue
+        :-2, echo Ambiguous - "\%a"         ; Matches too many
+             continue
+      }
+      switch \fword(\&k[\%n],2) {           ; Dispatch according to value
+         :9, echo Driving..., break
+         :8, echo Doing..., break
+         :7, echo Discussing..., break
+         :6, echo Living..., break
+         :5, echo Spending..., break
+         :4, echo { Commands (may be abbreviated):}
+             for \%i 1 \fdim(&k) 1 {
+                echo {  \%i. \fword(\&k[\%i],1) }
+             }
+             break
+         :0, exit 0 Bye!
+         :default, stop 1 Internal error
+      }
+  }
+
+   In this example, keywords are "drive", "do", "discuss", etc, and their
+   values are unique numbers (values need not be numbers, and there need
+   not be only one value -- there can be 0, 1, 2, or more of them). The
+   user types a command, which can be the whole word (like "help") or any
+   abbreviation (like "hel", "he", or just "h"). If this does not match
+   any keywords, \ftablelook() returns -1; if it matches more than one
+   (as would "d"), it returns -2. Otherwise the array index is returned,
+   1 or higher.
+
+   Given the array index \%n, we can get the table values as follows:
+
+  \fword(\&k[\%n],1) is the keyword (first field)
+  \fword(\&k[\%n],2) is the value (second field, in this case a number)
+
+   In our example, we use the value (number) as the SWITCH variable. As
+   noted, \fablelook() expects the array elements to contain multiple
+   fields separated by colon (:) (or other character that you specify,
+   e.g. \ftablelook(\%a,&a,^)) and when matching the keyword, ignores the
+   first delimiter and everything after it.
+     _________________________________________________________________
+
+    7.10.8. Hints for Using Arrays
+
+   C programmers are accustomed to out-of-bounds array references causing
+   core dumps or worse. In C-Kermit:
+
+     * A reference to an an out-of-bounds array element returns the empty
+       string.
+     * An attempt to set the value of an array element that is out of
+       bounds or that has not been declared simply fails.
+
+   C programmers expect an array of size nto have elements 0 through n-1.
+   Fortran programmers expect the same array to have elements 1 through
+   n. C-Kermit accommodates both styles; when you declare an array of
+   size n, it has n=1 elements, 0 through n, and you can use the array in
+   your accustomed manner, 0-based or 1-based.
+
+   However, note that C-Kermit has certain biases towards 1-based arrays:
+
+     * Assignment of file lists starts with element 1 ([602]Section
+       7.10.3).
+     * Assignment by \fsplit() starts with element 1 ([603]Section 7.3).
+     * Array initialization skips the 0th element. To initialize a
+       0-based array, use something like this:
+  declare \&a[3] = one two three
+  .\&a[0] = zero
+     * The ARRAY SORT command skips the 0th element unless you include
+       /RANGE:0
+     * The SHIFT command ignores element 0 of the \&_[] array.
+
+   The distinction between an array's dimensioned size and the number of
+   elements in the array is important when sorting. To illustrate:
+
+  declare \&a[100]                  ; Declare array &a with 100 elements
+  fopen /read \%c oofa.txt          ; Open a file
+  if fail...
+  for \%i 1 \fdim(&a) 1 {           ; Read the file into the array
+      fread \%c \&a[\%i]
+      if fail break
+  }
+  fclose \%c
+  if > \%i \fdim(&a) end 1 File has too many lines for array.
+  .\%n ::= \%i - 1
+  echo File has \%n line(s).
+
+   Let's say the file had 95 lines. This leaves elements 96-100 of the
+   array empty. Now suppose you sort the array and write out the result:
+
+  sort &a                           ; Sort the whole array
+  fopen /write \%o oofa.txt.sorted  ; Open an output file
+  if fail ...
+  for \%i 1 \%n 1 {                 ; Write out 95 records
+      fwrite /line \%o \&a[\%i]
+      if fail end 1 Write error
+  }
+  close write
+
+   You might be surprised at the contents of "oofa.txt.sorted" -- five
+   empty elements, 96-100, floated to the top of the array in the sort,
+   and since your write loop only had 95 iterations, the final 5 lines of
+   the sorted file are lost.
+
+   Therefore, when dealing with partially filled arrays -- especially
+   when sorting them -- remember to specify the number of elements. A
+   handy way of recording an array's "true" size is to put it in the 0th
+   element. That way, it "travels with the array". To illustrate
+   (continuing the previous example at the "close read" statement):
+
+  close read
+  if > \%i \fdim(&a) end 1 File has too many lines for array.
+  .\&a[0] ::= \%i - 1     ; Assign number of lines to \&a[0].
+  echo File has \&a[0] line(s).
+  sort /range:1:\&a[0] &a
+  open write oofa.txt.sorted
+  if fail ...
+  for \%i 1 \&a[0] 1 {
+      writeln file \&a[\%j]
+      if fail end 1 Write error
+  }
+  close write
+
+   Note the SORT switch, /RANGE:1:\&a[0]. This keeps the sort 1-based,
+   and uses element 0 of the array as its size indicator.
+
+   Finally, note that even though some commands or functions might put a
+   size in array element 0, no built-in functions or commands depend on a
+   size actually being there. Thus you are perfectly free to replace the
+   size with something else and treat the array as 0-based.
+     _________________________________________________________________
+
+    7.10.9. Do-It-Yourself Arrays
+
+   Kermit's \&x[] arrays are nice because of the accompanying built-in
+   functionality -- ARRAY commands, built-in functions that load and
+   search arrays, automatic evaluation of arithmetic expressions within
+   the subscript brackets, and so on. Yet they also have certain
+   limitations:
+
+    1. Except when created by dynamic loading (e.g. by \ffiles()) they
+       must be declared and dimensioned in advance.
+    2. Indices must be numeric, positive, and in range.
+    3. There can be only one dimension. Matrices or other
+       higher-dimensioned arrays are not available.
+
+   But none of this is to say you can't invent any kind of data structure
+   you like. In [604]Section 7.9.2 you can see some examples. Here's
+   another (courtesy of Dat Thuc Nguyen), in which a pair of matrices is
+   created and then added: no dimensioning necessary.
+
+  .row = 4
+  .col = 9
+
+  ; MACRO TO PRINT A MATRIX
+  define PMATRIX {
+      echo Matrix \%1:
+      for \%r 1 \m(row) 1 {
+          for \%c 1 \m(col) 1 {
+              xecho \flpad(\m(\%1[\%r][\%c]),4)
+          }
+          echo
+      }
+      echo
+  }
+  ; CREATE MATRICES A AND B
+  for \%r 1 \m(row) 1 {
+      for \%c 1 \m(col) 1 {
+          _eval A[\%r][\%c] \%r + \%c
+          _eval B[\%r][\%c] \%r * \%c
+      }
+  }
+  ; CREATE MATRIX C = SUM OF MATRIX A AND MATRIX B
+  for \%r 1 \m(row) 1 {
+      for \%c 1 \m(col) 1 {
+          _eval C[\%r][\%c] \m(A[\%r][\%c]) + \m(B[\%r][\%c])
+      }
+  }
+  pmatrix A  ; Print Matrix A
+  pmatrix B  ; Print Matrix B
+  pmatrix C  ; Print Matrix C
+
+   In the example, we use matrix-like notation to create macros with
+   names like "A[1][1]", "B[3][7]", and so on.
+     _________________________________________________________________
+
+    7.10.10. Associative Arrays
+
+   An associative array is a special kind of Do-It-Yourself array. It
+   differs from a regular array in that its indices need not be numbers
+   -- they can be anything at all -- words, filenames, names of months,
+   any character string at all, and that it doesn't have to be (and in
+   fact can't be) declared. An associative array element is simply a
+   macro whose name ends with an index enclosed in angle brackets, for
+   example:
+
+  file<oofa.txt>
+
+   More formally:
+
+  basename<index>
+
+   An associative array is a collection of all associative array elements
+   that have the same basename. Any number of associative arrays, each
+   with any number of elements, can exist at the same time.
+
+   An associative array element can be assigned a value, such as "1",
+   just like any other macro:
+
+  define file<oofa.txt> 1     ; Give "file<oofa.txt>" the value "1".
+
+   or:
+
+  assign file<oofa.txt> \%a   ; Give it the value of the variable \%a.
+
+   However, since an associative array element is a macro, it may not
+   have an empty (null) value, since assigning an empty value to a macro
+   undefines the macro.
+
+   You can refer to the value of an associative array element using the
+   familiar notation for macro values:
+
+  echo \m(file<oofa.txt>)     ; Echo the value of "file<oofa.txt>".
+
+   Associative arrays are most useful, however, when the value of the
+   index is a variable. In that case, you must use the "hidden" forms of
+   the DEFINE or ASSIGN commands that evaluate the macro name before
+   making the assignment (see [605]Using C-Kermit, page 457). Example:
+
+  define \%f oofa.txt
+  _define file<\%f> 1
+  echo file<\%f> = \m(file<\%f>)
+
+   prints:
+
+  file<oofa.txt> = 1
+
+   and then:
+
+  _increment file<\%f>
+  echo file<\%f> = \m(file<\%f>)
+
+   prints:
+
+  file<oofa.txt> = 2
+
+   What are associative arrays good for? The classic example is "word
+   counts": finding the number of times each word is used in a text
+   without knowing in advance what the words are. Without associative
+   arrays, your program would have to build a table of some kind, and
+   every time a word was encountered, look it up in the table to find its
+   position and counter, or add it to the table if it wasn't found -- a
+   time-consuming and laborious process. Associative arrays, however, let
+   you use the word itself as the table index and therefore sidestep all
+   the table building and lookups.
+
+   Let's work through a practical example. Suppose you have a
+   file-transfer log in which each line is composed of a number of
+   blank-separated fields, and the 9th field is a filename (which happens
+   to be the format of certain FTP server logs, as well as of C-Kermit's
+   new FTP-format transaction log, described in [606]Section 4.17.2), for
+   example:
+
+  Wed Jul 14 09:35:31 1999 22 xx.mit.edu 13412 /pub/ftp/mm/intro.txt ....
+
+   and you want to find out how many times each file was transferred. The
+   following code builds an associative array, file<>, containing the
+   counts for each file:
+
+  local name line max \%c \%n          ; Declare local variables
+  fopen /read \%c /var/log/ftpd.log    ; Open the log file ([607]Section 1.22)
+  if fail exit 1 Can't open log        ; Check
+  while true {                         ; Loop for each record
+      fread /line \%c line             ; Read a line
+      if fail break                    ; Check for end of file
+      .name := \fword(\m(line),9,{ })  ; Get 9th field = filename (Sec 7.3)
+      _increment file<\m(name)>        ; Increment its counter (Sec 7.9.2)
+  }
+  fclose \%c                           ; Close file when done.
+
+   Note that _INCREMENT (and INCREMENT, and [_]DECREMENT) treat an empty
+   (i.e. nonexistent) variable as having a value of 0, and therefore
+   creates the variable with a value of 1.
+
+   At this point, if you told Kermit to "show macro file<", it would list
+   the associative array. But since you don't necessarily know the names
+   of the files in the array, or even how many elements are in the array,
+   how can you use it in a script program?
+
+   The idea of creating macro names that include character-string indices
+   enclosed in angle brackets is perfectly arbitrary and doesn't depend
+   on any Kermit features that weren't already there -- we could just as
+   easily have used some other notation, such as "file[index]",
+   "file:index", or "file.index", and the code above would have worked
+   just as well (with the corresponding syntax adjustments). But to be
+   able to use an associative array in a program after the array is
+   built, we need a method of accessing all its elements without knowing
+   in advance what they are. That's where the chosen notation comes in.
+
+   First of all, any macro name that ends with "<xxx>" (where "xxx" is
+   any string) is case sensitive, unlike all other macro names, which are
+   case independent. To illustrate, "file<oofa.txt>" and "file<OOFA.TXT>"
+   are two distinct macros, whereas "OOFA", "Oofa", and "oofa", when used
+   as macro names, are all the same.
+
+   Second, the new \faaconvert() function converts an associative array
+   (that is, all macros with names of the form "base<index>" that have
+   the same "base" part) into a pair of regular arrays and returns the
+   number of elements:
+
+  \faaconvert(name,&a[,&b])
+
+   "name" is the name of the associative array, without the angle
+   brackets or index ("file" in our example).
+
+   The second argument is the name of a regular array in which to store
+   the indices of the associative array (filenames in our example); if an
+   array of this name already exists, it is destroyed unless the array is
+   LOCAL. The third argument is the name of another regular array in
+   which to store the values (the counts in our example), with the same
+   rules about array name collisions. If you care only about the indices
+   and not the values, you can omit the third argument to \faaconvert().
+   In any case, the associative array is converted, not copied: its
+   elements are moved to the specified regular arrays, so after
+   conversion the original associative array is gone.
+
+   As with other array-loading functions, \faaconvert() sets element 0 of
+   each array to the number of elements in the array.
+
+   To continue our example:
+
+  .max := 0                                   ; Maximum count
+  .\%n := \faaconvert(file,&a,&b)             ; Convert
+  for \%i 1 \%n 1 {                           ; Loop through values
+      echo \flpad(\%i,3). \&a[\%i]: \&b[\%i]  ; Echo this pair
+      if ( > \&b[\%i] \m(max) ) {             ; Check for new maximum
+          .name := \&a[\%i]
+          .max  := \&b[\%i]
+      }
+  }
+  echo Most popular file: \m(name), accesses: \m(max)
+
+   This lists the files and counts and then announces which file has the
+   highest count.
+
+   Now suppose you want to sort the array pair created from an
+   associative array. In our example, \&a[] contains filenames, and \&b[]
+   contains the associated counts. Here we take advantage of the ARRAY
+   SORT command's ability to sort a second array according to the first
+   one:
+
+  array sort /reverse /numeric &b &a          ; Descending sort by count
+
+   Now to see the top five files and their counts:
+
+  echo The top 5 files are:
+  for \%i 1 5 1 {                             ; Loop through top 5 values
+      echo \flpad(\%i,3). \&a[\%i]: \&b[\%i]  ; Echo this pair
+  }
+     _________________________________________________________________
+
+    7.10.11. Transferring Array Contents to Other Computers
+
+   The SEND /ARRAY:arrayname command ([608]Section 4.7.1) allows you to
+   send the contents of any array, or any contiguous segment of it, in
+   either text or binary mode to another computer, using Kermit protocol.
+   When used in conjunction with C-Kermit's other features (the array
+   features described in this section; the file i/o package from
+   [609]Section 1.22; its decision-making, pattern-matching, and string
+   manipulation capabilities, and so on) the possibilities are endless:
+   extracts of large files, remote database queries, ..., all without
+   recourse to system-dependent mechanisms such UNIX pipes and filters,
+   thus ensuring cross-platform portability of scripts that use these
+   features.
+
+   When sending an array in text mode, Kermit appends a line terminator
+   to each array element, even empty ones, and it also converts the
+   character set from your current FILE character-set to your current
+   TRANSFER character-set, if any. No conversions are made or line
+   terminations added in binary mode. For example, the following array:
+
+  dcl \&a[] = One Two Three Four Five Six
+
+   is sent as six lines, one word per line, in text mode, and as the bare
+   unterminated string "OneTwoThreeFourFiveSix" in binary mode.
+
+   You should always include a /TEXT or /BINARY switch in any SEND /ARRAY
+   command to force the desired transfer mode, otherwise you're likely to
+   be surprised by the effects described in [610]Section 4.3.
+
+   Here are some examples:
+
+   send /text /array:\&a[]
+          Sends the entire contents of the array \&a[] in text mode.
+          Since an as-name is not included, the receiver is told the
+          filename is _array_a_.
+
+   send /text /array:&a[]
+   send /text /array:a[]
+   send /text /array:&a
+   send /text /array:a
+          These are all equivalent to the previous example.
+
+   send /text /array:&a /as-name:foo.bar
+          As above, but the array is sent under the name foo.bar.
+
+   send /text /array:&a[100:199] /as:foo.bar
+          As above, but only the elements from 100 through 199 are sent.
+
+   In text-mode transfers, character sets are translated according to
+   your current settings, just as for text files. In binary mode, of
+   course, there is no character-set translation or other conversion of
+   any kind. But remember that array elements can not contain the NUL
+   (ASCII 0) character, since they are implemented as NUL-terminated
+   strings.
+
+   Here's an example that shows how to send all the lines (up to 1000 of
+   them) from a file animals.txt that contain the words "cat", "dog", or
+   "hog" (see [611]Section 4.9 about pattern matching):
+
+  declare \&a[1000]
+  fopen /read \%c animals.txt
+  if fail exit 1
+  .\%i = 0
+  while true {
+      fread \%c line
+      if fail break
+      if match {\m(line)} {*{cat,[dh]og}*} {
+          increment \%i
+          if ( > \%i \fdim(&a) ) break
+          .\&a[\%i] := \m(line)
+      }
+  }
+  fclose \%c
+  send /array:a[1:\%i] /text
+
+   Note that we are careful to send only the part of the array that was
+   filled, not the entire array, because there are likely to be lots of
+   unused elements at the end, and these would be sent as blank lines
+   otherwise.
+
+   This example raises an interesting question: what if we want to send
+   ALL the matching lines, even if there are more than 1000 of them, but
+   we don't know the number in advance? Clearly the problem is limited by
+   Kermit's (and the computer's) memory. If there are a thousand trillion
+   matching lines, they most likely will not fit in memory, and in this
+   case the only solution is to write them first to a temporary file on
+   mass storage and then send the temporary file and delete it
+   afterwards.
+
+   However, when the selection is likely to fit in memory, the
+   once-familiar technique of initial allocation with extents can be
+   used:
+
+  if match {\m(line)} {*{cat,[dh]og}*} {
+      increment \%i
+      if ( > \%i \fdim(&a) ) {
+          array resize a \fdim(&a)+100
+          if fail stop 1 MEMORY FULL
+          echo NEW DIMENSION: \fdim(&a)
+      }
+      .\&a[\%i] := \m(line)
+  }
+
+   This grows the array in chunks of 100 as needed.
+     _________________________________________________________________
+
+  7.11. OUTPUT Command Improvements
+
+   LINEOUT [ text ]
+          This command is exactly like OUTPUT, except it supplies a
+          carriage return at the end of the text. "lineout exit" is
+          exactly the same as "output exit\13".
+
+   SET OUTPUT SPECIAL-ESCAPES { ON, OFF }
+          This command lets you tell C-Kermit whether to process \N, \L,
+          and \B specially in an OUTPUT command, as distinct from other \
+          sequences (such as \%a, \13, \v(time), etc). Normally the
+          special escapes are handled. Use SET OUTPUT SPECIAL-ESCAPES OFF
+          to disable them.
+
+   Disabling special escapes is necessary in situations when you need to
+   transmit lines of data and you have no control over what is in the
+   lines. For example, a file oofa.txt that contains:
+
+  This is a file
+  It has \%a variables in it
+  And it has \B in it.
+  And it has \L in it.
+  And it has \N in it.
+  And this is the last line.
+
+   can be sent like this:
+
+  local line
+  set output special-escapes off
+  fopen /read \%c oofa.txt
+  if fail stop 1 Can't open oofa.txt
+  while success {
+      fread \%c line
+      if fail break
+      ; Add filtering or processing commands here...
+      output \m(line)\13
+  }
+     _________________________________________________________________
+
+  7.12. Function and Variable Diagnostics
+
+   In C-Kermit 6.0 and earlier, the only diagnostic returned by a failing
+   function call was an empty value, which (a) could not be distinguished
+   from an empty value returned by a successful function call; (b) did
+   not give any indication of the cause of failure; and (c) did not cause
+   the enclosing statement to fail. C-Kermit 7.0 corrects these
+   deficiencies.
+
+   SET FUNCTION DIAGNOSTICS { ON, OFF }
+          when ON, allows built-in functions to return diagnostic
+          messages when improperly referenced, instead of an empty
+          string. FUNCTION DIAGNOSTICS are ON by default. When OFF,
+          improperly referenced functions continue to return an empty
+          string. This command also affects built-in variables; in this
+          case, an error message is returned only if the variable does
+          not exist. When FUNCTION DIAGNOSTICS are ON, the error message
+          is also printed.
+
+   For variables, the only message is:
+
+  <ERROR:NO_SUCH_VARIABLE:\v(name)>
+
+   where "name" is the name of the nonexistent variable.
+
+   For functions, the diagnostic message is:
+
+  <ERROR:message:\fname()>
+
+   where "message" is replaced by a message, and "name" is replaced by
+   the function name, e.g. <ERROR:ARG_NOT_NUMERIC:\fmod()>. Messages
+   include:
+
+  ARG_BAD_ARRAY       An argument contains a malformed array reference.
+  ARG_BAD_DATE        An argument contains a malformed date and/or time.
+  ARG_BAD_PHONENUM    An argument contains a malformed telephone number.
+  ARG_BAD_VARIABLE    An argument contains a malformed \%x variable.
+  ARG_INCOMPLETE      An argument is incomplete (e.g. a broken Base64 string).
+  ARG_EVAL_FAILURE    An argument could not be evaluated (internal error).
+  ARG_NOT_ARRAY       An argument references an array that is not declared.
+  ARG_NOT_NUMERIC     An argument that must be integer contains non-digits.
+  ARG_NOT_FLOAT       An argument has bad floating-point number format.
+  ARG_NOT_VARIABLE    An argument that must be a variable is not a variable.
+  ARG_OUT_OF_RANGE    An argument's numeric value is too big or too small,
+                      or an argument contains illegal characters (e.g. a hex
+                      or Base-64 string).
+  ARG_TOO_LONG        An argument's value is too long.
+  ARRAY_FAILURE       Failure to create an array.
+  DIVIDE_BY_ZERO      Execution of the function would cause division by zero.
+  FLOATING_POINT_OP   Execution error in a floating-point operation.
+  FILE_NOT_FOUND      Filename argument names a file that can't be found.
+  FILE_NOT_READABLE   Filename argument is not a regular file.
+  FILE_NOT_ACCESSIBLE Filename argument names a file that is read-protected.
+  FILE_ERROR          Other error with filename argument.
+  FILE_NOT_OPEN       A file function was given a channel that is not open.
+  FILE_ERROR_-n       A file function got error -n ([612]Section 1.22).
+  LOOKUP_FAILURE      Error looking up function (shouldn't happen).
+  MALLOC_FAILURE      Failure to allocate needed memory (shouldn't happen).
+  NAME_AMBIGUOUS      The function is not uniquely identified.
+  MISSING_ARG         A required argument is missing.
+  NO_SUCH_FUNCTION    An argument references a function that is not defined.
+  NO_SUCH_MACRO       An argument references a macro that is not defined.
+  RESULT_TOO_LONG     The result of a function is too long.
+  UNKNOWN_FUNCTION    Internal error locating function (shouldn't happen).
+
+   Examples:
+
+  assign \%m \fmod()
+  ?<ERROR:MISSING_ARG:\fmod()>
+  echo "\fcontents(\%m)"
+  "<ERROR:MISSING_ARG:\fmod()>"
+  echo \fmod(3,x)
+  ?<ERROR:ARG_NOT_NUMERIC:\fmod()>
+  echo \fmod(3,4-2*2)
+  ?<ERROR:DIVIDE_BY_ZERO:\fmod()>
+
+   Notice the use of \fcontents() in echoing the value of a variable that
+   contains a returned error message. That's because the error message
+   includes the name of the variable or function that failed, so you must
+   use \fcontents() to prevent it from being evaluated again -- otherwise
+   the same error will occur.
+
+   The handling of function and variable errors is controlled by:
+
+   SET FUNCTION ERROR { ON, OFF }
+          Tells whether invalid function calls or variable references
+          should cause command errors. FUNCTION ERROR is ON by default.
+          When ON, and an error is diagnosed in a built-in function or
+          variable, the command that includes the function call or
+          variable reference fails. The failing command can be handled in
+          the normal way with IF FAILURE / IF SUCCESS, SET TAKE ERROR, or
+          SET MACRO ERROR.
+
+   When FUNCTION DIAGNOSTICS is OFF, there is no error message.
+
+   SHOW SCRIPTS displays the current FUNCTION DIAGNOSTICS and ERROR
+   settings.
+     _________________________________________________________________
+
+  7.13. Return Value of Macros
+
+   In C-Kermit 5A and 6.0, there are two ways to return one level from a
+   macro: RETURN value and END number text. When RETURN is used, the
+   value, which can be a number or a text string, is assigned to
+   \v(return). When END was used, however, \v(return) was not set.
+   SUCCESS/FAILURE was set according to whether the number was zero, and
+   the text was printed, but the actual value of the number was lost.
+
+   In C-Kermit 7.0, the END number is available in the \v(return)
+   variable.
+     _________________________________________________________________
+
+  7.14. The ASSERT, FAIL, and SUCCEED Commands.
+
+   The ASSERT command is just like the IF command, but without a command
+   to execute. It simply succeeds or fails, and this can be tested by a
+   subsequent IF SUCCESS or IF FAILURE command. Example:
+
+  ASSERT = 1 1
+  IF SUCCESS echo 1 = 1.
+
+   The FAIL command does nothing, but always fails. The SUCCEED command
+   does nothing, but always succeeds.
+
+   These commands are handy in debugging scripts when you want to induce
+   a failure (or success) that normally would not occur, e.g. for testing
+   blocks of code that normally are not executed.
+     _________________________________________________________________
+
+  7.15. Using Alarms
+
+   Alarms may be set in two ways:
+
+   SET ALARM number
+          Sets an alarm for the given number of seconds "from now", i.e.
+          in the future, relative to when the SET ALARM command was
+          given. Examples:
+
+  set alarm 60        ; 60 seconds from now
+  set alarm +60       ; The same as "60"
+  set alarm -60       ; Not legal - you can't set an alarm in the past.
+  set alarm 60*60     ; 60 minutes from now.
+  set alarm \%a+10    ; You can use variables, etc.
+
+   SET ALARM hh:mm:ss
+          Sets an alarm for the specified time. If the given time is
+          earlier than the current time, the alarm is set for the given
+          time in the next day. You may give the time in various formats:
+
+  set alarm 15:00:00  ; 3:00:00pm
+  set alarm 3:00:00pm ; 3:00:00pm
+  set alarm 3:00pm    ; 3:00:00pm
+  set alarm 3pm       ; 3:00:00pm
+
+   SHOW ALARM
+          Displays the current alarm, if any, in standard date-time
+          format (see [613]Section 1.6): yyyymmdd hh:mm:ss.
+
+   IF ALARM command
+          Executes the command if an alarm has been set and the alarm
+          time has passed.
+
+   IF ALARM { command-list } [ ELSE { command-list } ]
+          Executes the command-list if an alarm has been set and the
+          alarm time has passed. Otherwise, if an ELSE part is given, its
+          command-list is executed.
+
+   CLEAR ALARM
+          Clears the alarm.
+
+   Only one alarm may be set at a time.
+
+   Example: Suppose you have a script that is always running, and that
+   transfers files periodically, and that keeps a transaction log.
+   Suppose you want to start a new transaction log each day:
+
+  log transactions \v(date).log
+  set alarm 00:00:00                     ; Set an alarm for midnight
+  while true {                           ; Main script loop
+      xif alarm {                        ; If the alarm time is past...
+          close transactions             ; Close current log
+          log transactions \v(date).log  ; Start new one
+          pause 1                        ; To make sure 00:00:00 is past
+          set alarm 00:00:00             ; Set a new alarm
+      }
+      ; put the rest of the script here...
+  }
+
+   Note that IF ALARM -- no matter whether it succeeds or fails -- does
+   NOT clear an expired alarm. Thus, once an alarm has expired, every IF
+   ALARM will succeed until the alarm is cleared (with the CLEAR ALARM
+   command) or reset with a new SET ALARM command.
+     _________________________________________________________________
+
+  7.16. Passing Arguments to Command Files
+
+   Beginning in version 7.0, C-Kermit accepts arguments on the TAKE
+   command line, for example:
+
+  C-Kermit> take oofa.ksc one two {this is three} four
+
+   This automatically sets the variables \%1 through \%9 to the
+   arguments, and \%0 to the name of the file, in this case:
+
+  \%0 = /usr/olga/oofa.ksc
+  \%1 = one
+  \%2 = two
+  \%3 = this is three
+  \%4 = four
+
+   and \%5..\%9 are undefined (empty). Arguments past the ninth are
+   available in the \&_[] argument-vector array ( [614]Section 7.5).
+
+   The variables are those at the current macro level. Thus, if the TAKE
+   command is executed from within a macro, the macro's arguments are
+   replaced by those given on the TAKE command line (but only if at least
+   one argument is given). The command shown above is exactly equivalent
+   to:
+
+  assign \%0 /usr/olga/oofa.ksc
+  assign \%1 one
+  assign \%2 two
+  assign \%3 this is three
+  assign \%4 four
+  assign \%5
+  assign \%6
+  assign \%7
+  assign \%8
+  assign \%9
+  take oofa.ksc
+
+   Remember, the variables \%0..\%9 are on the macro call stack, and
+   command files are independent of the macro stack. Thus, if a command
+   file TAKEs another command file and passes arguments to it, the
+   variables are changed from that point on for both files, and so forth
+   for all levels of nested command files without intervening macro
+   invocations.
+
+   It would have been possible to change C-Kermit to use the overall
+   command stack, rather than the macro stack, for arguments -- this
+   would have made TAKE work exactly like DO, which is "nicer", but it
+   would also have broken countless existing scripts. However, the new
+   SHIFT command ([615]Section 7.5) makes it possible to create an
+   alternative TAKE command that does indeed save and restore the
+   argument variables at its own level around execution of a command
+   file:
+
+  define mtake {
+     local \%f
+     assign \%f \fcontents(\%1)
+     shift
+     take \%f
+  }
+
+   C-Kermit 7.0 also supports a new, easier way to pass arguments to
+   scripts from the system command line:
+
+  kermit filename arg1 arg2 arg3 ...
+
+   in which arg1, arg2, arg3 (etc) are arguments for the script (whose
+   filename is given), and are assigned to \%1, \%2, ... \%9. The
+   filename is assigned to \%0. This applies equally to "Kerbang" scripts
+   in UNIX ([616]Section 7.19). For example, suppose you have a file
+   called "showargs" containing the following lines:
+
+  #!/usr/local/bin/kermit +
+  echo Hello from \%0
+  show args
+  exit
+
+   (except not indented, since the "#!" line must be on the left margin).
+   If you give this file execute permission:
+
+  chmod +x showargs
+
+   then you can run it exactly as you would run a UNIX shell script,
+   e.g.:
+
+  $ showargs one two three
+  Hello from /usr/olga/showargs
+  Top-level arguments (\v(argc) = 4):
+   \&_[0] = /usr/olga/showargs
+   \&_[1] = one
+   \&_[2] = two
+   \&_[3] = three
+
+   Furthermore, the \&_[] array now contains the filename, if one was
+   given as the first command line argument, or it is a "Kerbang" script,
+   in element 0.
+
+   Otherwise element 0 is program name, and elements 1 through \v(argc)-1
+   contain the command-line arguments, if any, that appear after "--" or
+   "=", if any. This array is saved and restored around macro calls;
+   recall that inside macros it contains the macro argument vector
+   (allowing you to access arguments programmatically, and to have more
+   than 9 of them).
+
+   At top level, notice the difference between the \&@[] and \&_[]
+   arrays. The former includes C-Kermit options; the latter omits them.
+     _________________________________________________________________
+
+  7.17. Dialogs with Timed Responses
+
+   The ASK, ASKQ, GETOK, and GETC commands (let's call them the
+   "ASK-class commands") let you write scripts that carry on dialogs with
+   the user, asking them for text, a Yes/No answer, or a character,
+   respectively. Prior to C-Kermit 7.0, these questions would always wait
+   forever for an answer. In C-Kermit 7.0, you may specify a time limit
+   for them with the new command:
+
+   SET ASK-TIMER number
+          Sets a time-limit on ASK-CLASS commands to the given number of
+          seconds. If the number is 0 or less, there is no time limit and
+          these commands wait forever for a response. Any timer that is
+          established by this command remains in effect for all future
+          ASK-class commands until another SET ASK-TIMER command is given
+          (e.g. with a value of 0 to disable ASK timeouts).
+
+   IF ASKTIMEOUT command
+          An ASK-class command that times out returns a failure status.
+          You can test explicitly for a timeout with:
+     _________________________________________________________________
+
+  7.18. Increased Flexibility of SWITCH Case Labels
+
+   Prior to C-Kermit 7.0 / K95 1.1.19, the case labels in SWITCH
+   statements were string constants.
+
+   Now case labels can be variables, function calls, or any mixture of
+   these with each other and/or with regular characters.
+
+   Furthermore, after the case label is evaluated, it is treated not as a
+   string constant, but as a pattern against which the SWITCH variable is
+   matched ([617]Section 4.9.1).
+
+   This introduces a possible incompatibility with previous releases,
+   since the following characters in case labels are no longer taken
+   literally:
+
+  \ * ? [ {
+
+   Any scripts that previously included any of these characters in case
+   labels must now quote them with backslash (\).
+     _________________________________________________________________
+
+  7.19. "Kerbang" Scripts
+
+   In UNIX only, Kermit scripts can be stored in files and run
+   "directly", without starting Kermit first (as noted on page 467 of the
+   manual), just as a shell script can be "run" as if it were a program.
+   This section amplifies on that idea a bit, and presents some new
+   aspects of version 7.0 that make it easier to write and run Kermit
+   scripts directly.
+
+     NOTE: On non-UNIX platforms, such as VMS or Windows, Kerbang
+     scripts can be run as "kermit + scriptfilename arg1 arg2 arg3 ...".
+     Windows 95/98/NT file associations do not allow for the passing of
+     parameters. In VMS, however, you can achieve the Kerbang effect by
+     defining a symbol, as in this example:
+
+  $ autotelnet :== "$SYS$TOOLS:KERMIT.EXE + AUTOTELNET.KSC"
+
+     and then running the script like any other command:
+
+  $ autotelnet xyzcorp.com myuserid
+
+     See [618]Section 9.3 for an explanation of the "+" symbol.
+
+   UNIX shell scripts can specify which shell should run them by
+   including a "shebang" line at the top, e.g.:
+
+  #!/bin/sh
+
+   (but not indented; the shebang line must be on the left margin). The
+   term "shebang" is a contraction of "shell" and "bang". "Bang" is a
+   slang word for the exclamation mark ("!"); "shebang" itself is an
+   American slang word used in in the phrase "the whole shebang".
+
+   We can run Kermit scripts directly too, by including a "shebang" line
+   that names Kermit as the "shell"; thus we call these "Kerbang"
+   scripts. This mechanism has been considerably simplified in C-Kermit
+   7.0 to facilitate C-Kermit's use a scripting tool just like any of the
+   UNIX shells or scripting languages. The rules are the same as for
+   shell scripts:
+
+    1. The first line of the Kermit script must begin with "#!"
+       immediately followed by the full pathname of the program that will
+       execute the script (in this case, C-Kermit rather than a UNIX
+       shell), followed by any Kermit command-line options. To suppress
+       execution of the C-Kermit initialization file and to make command
+       line arguments available to the script, the final option should be
+       "+":
+  #!/usr/local/bin/kermit +
+       Some users have reported that in some circumstances a space might
+       be necessary after the plus sign; this depends on your shell -- it
+       has nothing to do with Kermit. In most cases, no space is needed.
+    2. The file must have execute permission (granted via "chmod +x
+       filename").
+
+   When C-Kermit is invoked from a Kerbang script (or from the system
+   prompt with a "+" command-line argument, which amounts to the same
+   thing), the following special rules apply:
+
+    1. The C-Kermit initialization file is NOT executed automatically. If
+       you want it to be executed, include a TAKE command for it in the
+       script, e.g. "take \v(home).kermrc". (In previous releases, the
+       initialization file was always executed, with no way to prevent it
+       except for the user to include Kermit-specific command line
+       options which had nothing to do with the script). Many scripts
+       have no need for the standard Kermit initialization file, which is
+       quite lengthy and not only delays startup of the script, but also
+       spews forth numerous messages that are most likely unrelated to
+       the script.
+    2. If the initialization file is not executed, neither is your
+       customization file, since the initialization file is the command
+       file from which the customization file is TAKEn. Again, you can
+       include a TAKE command for the initialization file if desired, or
+       for the customization file by itself, or for any other file.
+    3. C-Kermit does not process command-line arguments at all. Instead,
+       it passes all words on the command line after the "+" to the
+       script as \%0 (the script name), \%1..\%9 (the first nine
+       arguments), as well as in the argument vector array \&_[]. The
+       variable \v(argc) is set to the total number of "words" (as passed
+       by the shell to Kermit) including the script name. Quoting and
+       grouping rules are those of the shell.
+    4. At any point where the script terminates, it must include an EXIT
+       command if you want it to exit back to the shell; otherwise
+       C-Kermit enters interactive prompting mode when the script
+       terminates. The EXIT command can include a numeric status to be
+       returned to the shell (0, 1, etc), plus an optional message.
+
+   Here is a simple Kerbang script that prints its arguments:
+
+  #/usr/local/bin/kermit +
+  echo Hello from \%0
+  for \%i 0 \v(argc)-1 1 {
+      echo \%i. "\&_[\%i]"
+  }
+  exit 0
+
+   Save this file as (say) "showargs", then give it execute permission
+   and run it (the \&_[] array is the same as \%0..\%9, but allows you to
+   refer to argument variables programmatically; see [619]Section 7.5).
+   (Yes, you could substitute SHOW ARGUMENTS for the loop.)
+
+  $ chmod +x showargs
+  $ ./showargs one "this is two" three
+
+   The script displays its arguments:
+
+  Hello from /usr/olga/showargs
+  0. "/usr/olga/showargs"
+  1. "one"
+  2. "this is two"
+  3. "three"
+  $
+
+   Notice that no banners or greetings are printed and that startup is
+   instantaneous, just like a shell script. Also notice that grouping of
+   arguments is determined by *shell* quoting rules, not Kermit ones,
+   since the command line is parsed by the shell before Kermit ever sees
+   it.
+
+   Of course you can put any commands at all into a Kerbang script. It
+   can read and write files, make connections, transfer files, anything
+   that Kermit can do -- because it *is* Kermit. And of course, Kerbang
+   scripts can also be executed from the Kermit prompt (or from another
+   script) with a TAKE command; the Kerbang line is ignored since it
+   starts with "#", which is a comment introducer to Kermit just as it is
+   to the UNIX shell. In VMS and other non-UNIX platforms, the Kerbang
+   line has no effect and can be omitted.
+
+   It might be desireable for a script to know whether it has been
+   invoked directly from the shell (as a Kerbang script) or by a TAKE
+   command given to the Kermit prompt or in a Kermit command file or
+   macro. This can be done as in this example:
+
+  #!/usr/local/bin/kermit +
+  assign \%m \fbasename(\%0)
+  define usage { exit 1 {usage: \%m phonenumber message} }
+  define apage { (definition of APAGE...) } ; (See [620]book pp.454-456)
+  xif equal "\%0" "\v(cmdfil)" {
+      if not def \%1 usage
+      if not def \%2 usage
+      apage {\%1} {\%2}
+      exit \v(status)
+  }
+
+   In a Kerbang script, \%0 and \v(cmdfile) are the same; both of them
+   are the name of the script. When a script is invoked by a Kermit TAKE
+   command, \%0 is the name of the Kermit program, but \v(cmdfile) is the
+   name of the script. In the example above, a macro called APAGE is
+   defined. If the script was invoked directly, the APAGE macro is also
+   executed. Otherwise, it is available for subsequent and perhaps
+   repeated use later in the Kermit session.
+
+   An especially handy use for Kerbang scripts is to have the
+   initialization file itself be one. Since the standard initialization
+   file is rather long and time-consuming to execute, it is often
+   overkill if you want to start Kermit just to transfer a file. Of
+   course there are command-line switches to suppress initialization-file
+   execution, etc, but another approach is to "run" the initialization
+   file when you want its features (notably the services directory), and
+   run C-Kermit directly when you don't. A setup like this requires that
+   (a) the C-Kermit initialization file is configured as a Kerbang script
+   (has #!/path.../kermit as first line), has execute permission, and is
+   in your PATH; and (b) that you don't have a .kermrc file in your login
+   directory.
+     _________________________________________________________________
+
+  7.20. IF and XIF Statement Syntax
+
+   The IF command has been improved in two significant ways in C-Kermit
+   7.0, described in the following subsections. All changes are backwards
+   compatible.
+
+    7.20.1. The IF/XIF Distinction
+
+   The distinction between IF and XIF is no longer important as of
+   C-Kermit 7.0. You should be able to use IF in all cases (and of
+   course, also XIF for backwards compatibility). In the past, IF was
+   used for single-command THEN parts, followed optionally by a separate
+   ELSE command:
+
+  IF condition command1    ; THEN part
+  ELSE command2            ; ELSE part
+
+   whereas XIF was required if either part had multiple commands:
+
+  XIF condition { command, command, ... } ELSE { command, command, ... }
+
+   The syntactic differences were primarily that IF / ELSE was two
+   commands on two separate lines, whereas XIF was one command on one
+   line, and that XIF allowed (and in fact required) braces around its
+   command lists, whereas IF did not allow them.
+
+   Furthermore, the chaining or nesting of parts and conditions was
+   inconsistent. For example, the IF command could be used like this:
+
+  IF condition command
+  ELSE IF condition command
+  ELSE IF condition command
+  ELSE IF condition command
+  ...
+
+   but XIF could not. C-Kermit 7.0 accepts the old syntax and executes it
+   the same as previous versions, but also accepts a new unified and more
+   convenient syntax:
+
+   IF condition command-list [ ELSE command-list ]
+
+   or:
+
+IF condition command-list
+ELSE command-list
+
+   in which the ELSE part is optional, and where command-list can be a
+   single command (with or without braces around it) or a list of
+   commands enclosed in braces. Examples:
+
+   Example 1:
+
+  IF condition { command1, command2 } ELSE { command3, command4 }
+
+   Example 2 (same as Example 1):
+
+  IF condition {
+     command1
+     command2
+  } ELSE {
+     command3
+     command4
+  }
+
+   Example 3 (same as 1 and 2):
+
+  IF condition {
+     command1
+     command2
+  }
+  ELSE { command3, command4 }
+
+   Example 4 (same as 1-3):
+
+  IF condition {
+     command1
+     command2
+  }
+  ELSE {
+     command3
+     command4
+  }
+
+   Example 5 (ELSE can be followed by another command):
+
+  IF condition {
+     command1
+     command2
+  } ELSE IF condition {
+     command3
+     command4
+  } ELSE {
+     command5
+     command6
+  }
+
+   Example 5 suggests other possibilities:
+
+  IF condition {
+     command1
+     command2
+  } ELSE FOR variable initial final increment {
+     command3
+     command4
+  }
+
+   And this too is possible, except for some non-obvious quoting
+   considerations:
+
+  dcl \&a[6] = one two three four five six
+
+  IF < \%n 3 {
+      echo \\%n is too small: \%n
+  } ELSE FOR \\%i 1 \\%n 1 {
+      echo \\%i. \\&a[\\%i]
+  }
+
+   (The loop variable must be quoted in this context to prevent premature
+   evaluation.)
+     _________________________________________________________________
+
+    7.20.2. Boolean Expressions (The IF/WHILE Condition)
+
+   Prior to C-Kermit 7.0, the IF and WHILE commands accepted only a
+   single Boolean ("true or false") assertion, e.g. "if > \%m 0 command"
+   or "if exist filename command". There was no way to form Boolean
+   expressions and, in particular, nothing that approached a Boolean OR
+   function (AND could be simulated by concatenating IF statements: "if
+   condition1 if condition2..").
+
+   C-Kermit 7.0 (and K95 1.1.19) allow grouping of Boolean assertions
+   using parentheses and combining them using AND (or &&) and OR (or ||).
+   Each of these operators -- including the parentheses -- is a field and
+   must be set off by spaces. AND has higher precedence than OR, NOT has
+   higher precedence than AND, but parentheses can be used to force any
+   desired order of evaluation. The old syntax is still accepted.
+
+   Here are some examples:
+
+  define \%z 0                          ; Define some variables
+  define \%n 1                          ; for use in the examples.
+
+  if > \%n \%z echo \%n is greater.     ; Original format - still accepted.
+  if ( > \%n \%z ) echo \%n is greater. ; Parentheses may be used in 7.0.
+  if ( > \%n \%z && not = \%z 0 ) ...   ; Two assertions combined with AND.
+  if ( > \%n \%z and not = \%z 0 ) ...  ; Same as previous ("and" = "&&").
+  if ( > \%n \%z || not = \%z 0 ) ...   ; Two assertions combined with OR.
+  if ( > \%n \%z or not = \%z 0 ) ...   ; Same as previous ("or" = "||").
+  if ( > \%n \%z || != \%z 0 ) ...      ; Ditto ("!=" = "not =").
+  while ( 1 ) { ... }                   ; Just like C.
+
+   Notice the spaces around all operators including the parentheses --
+   these are required. The following examples show how parentheses can be
+   used to alter the precedence of the AND and OR operators:
+
+  if ( false || false && false || true ) ,..         ; True
+  if ( false || ( false && false ) || true ) ...     ; Same as previous
+  if ( ( false || false ) && ( false || true ) ) ... ; False
+
+   Similarly for NOT:
+
+  if ( not true && false ) ...          ; False (NOT binds to TRUE only)
+  if ( ( not true ) && false ) ...      ; Same as previous
+  if ( not ( true && false ) ) ...      ; True (NOT binds to (TRUE && FALSE))
+
+   Notes:
+
+    1. The syntax of the Boolean expression itself has not changed; each
+       expression begins with a keyword or token such as "EXIST", ">", or
+       "=", etc; operators such as "<", "=", and ">" do not go between
+       their operands but precede them as before; this might be called
+       "reverse reverse Polish notation"; it allows deterministic
+       on-the-fly parsing of these expressions at the C-Kermit> prompt as
+       well as in scripts, and allows ?-help to be given for each item
+       when IF or WHILE commands are typed at the prompt.
+    2. Parentheses are required when there is more than one Boolean
+       assertion.
+    3. Parentheses are not required, but are allowed, when there is only
+       one Boolean assertion.
+    4. Evaluation of Boolean assertions occurs left to right, but the
+       resulting Boolean expression is evaluated afterwards according to
+       the rules of precedence. All Boolean assertions are always
+       evaluated; there is no "early stopping" property and therefore no
+       question about when or if side effects will occur -- if any
+       Boolean assertion has side effects, they will always occur.
+
+   Constructions of arbitrary complexity are possible, within reason.
+
+   Also see [621]Section 7.4 for new IF / WHILE conditions.
+     _________________________________________________________________
+
+  7.21. Screen Formatting and Cursor Control
+
+   C-Kermit 7.0 adds a simple way to create formatted screens, the SCREEN
+   command:
+
+   SCREEN { CLEAR, CLEOL, MOVE-TO row [ column ] }
+          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. The UNIX version uses terminfo or
+          termcap (not curses); the VMS version uses SMG; K-95 uses its
+          built in screen manager.
+
+   SCREEN CLEAR
+          Moves the cursor to home position and clears the entire screen.
+          Synonyms: CLEAR COMMAND-SCREEN ALL (K-95 only), CLS, CLEAR
+          SCREEN.
+
+   SCREEN CLEOL
+          Clears from the current cursor position to the end of the line.
+          Synonym: CLEAR COMMAND-SCREEN EOL (K-95 only)
+
+   SCREEN MOVE-TO 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.
+
+   These escape sequences used by these commands depends on the platform.
+   In UNIX, your TERM environment variable is used to query the
+   terminfo/termcap database; if the query fails, ANSI/VT100 sequences
+   are used. In VMS, the SMG library is used, which sends sequences based
+   on your VMS terminal type. K95 does its own screen control. On other
+   platforms (such as AOS/VS, VOS, etc), screen formatting is not
+   supported, and the SCREEN command does nothing.
+
+   The three SCREEN actions can be used in scripts to produce menus,
+   formatted screens, dynamic displays, etc. Related variables include:
+
+  \v(terminal)     The type terminal C-Kermit thinks you have.
+  \v(rows)         The number of rows C-Kermit thinks your terminal has.
+  \v(columns)      The number of columns C-Kermit thinks your terminal has.
+
+   And functions:
+
+  \fscrncurx()     The current X coordinate of the cursor (K-95 only).
+  \fscrncury()     The current Y coordinate of the cursor (K-95 only).
+  \fscrnstr(x,y,n) The string of length nat position (x,y) (K-95 only).
+
+   And commands:
+
+  ECHO string      Writes string + CRLF at the current cursor position.
+  XECHO string     Writes string at current cursor position; CRLF not supplied.
+  GETC v prompt    Issues prompt, reads one character into variable v, no echo.
+
+   And special characters:
+
+  Ctrl-L           At the C-Kermit> command prompt, or in a C-Kermit command,
+                   works like Return or Enter, but also clears the screen
+
+   Example 1: A macro that prints a message \%1 at cursor position
+   (\%2,\%3):
+
+  define MSG {
+      if not def \%3 def \%3 0             ; Default column to 0
+      if > \v(argc) 2 screen move \%2 \%3  ; Move to given row/col (if any)
+      screen cleol                         ; Clear to end of line
+      if def \%1 xecho \fcontents(\%1)     ; Print message (if any)
+  }
+
+   Example 2: A macro put the cursor on the bottom screen line, left
+   margin:
+
+  define BOT {
+      screen move \v(rows) 0
+  }
+
+   Example 3: A macro to center message \%1 on line \%2.
+
+  define CENTER {
+      if not def \%2 def \%2 1
+      .\%x ::= (\v(cols)-\flen(\%1))/2
+      msg {\%1} {\%2} {\%x}
+  }
+
+   Example 4: A simple menu (building on Examples 1-3):
+
+  def \%c 0                             ; Menu choice variable
+  screen clear                          ; Clear the screen
+  center {Welcome to This Menu} 2       ; Display the menu
+  msg {Choices:} 4
+  msg { 1. File} 6
+  msg { 2. Edit} 7
+  msg { 3. Exit} 8
+  while ( != \%c 3 ) {                  ; Read and verify choice
+      while true {                      ; Keep trying till we get a good one
+          screen move 10                ; Move to line 10
+          screen cleol                  ; Clear this line
+          getc \%c {Your choice: }      ; Prompt and get and echo 1 character
+          xecho \%c
+          if ( not numeric \%c ) { msg {Not numeric - "\%c"} 12, continue }
+          if ( >= \%c 1 && <= \%c 3 ) break
+          msg {Out of range - "\%c"} 12
+      }
+      switch \%c {                      ; Valid choice - execute it.
+        :1, msg {Filing... } 12, break
+        :2, msg {Editing...} 12, break
+        :3, msg {Exiting...} 12, break
+      }
+  }
+  echo Bye                              ; Exit chosen - say goodbye.
+  bot                                   ; Leave cursor at screen bottom.
+  exit                                  ; And exit.
+
+   Similar scripts can work over the communication connection; substitute
+   INPUT and OUTPUT for GETC and ECHO/XECHO.
+     _________________________________________________________________
+
+  7.22. Evaluating Arithmetic Expressions
+
+   A new arithmetic operator was added to the list recognized by the
+   EVALUATE command, the \feval() function, and which can also be used
+   anywhere else arithmetic expressions are accepted (numeric command
+   fields, array subscripts, etc):
+
+   Prefix "!"
+          This operator inverts the "truth value" of the number or
+          arithmetic expression that follows. If the value of the operand
+          is 0, the result is 1. If the value is nonzero, the result is
+          0.
+
+   Examples:
+
+  set eval old
+  evaluate 0
+  0
+
+  evaluate !0
+  1
+
+  evaluate !3
+  0
+
+  evaluate !(-3)
+  0
+
+  .\%a = 1
+  .\%b = 0
+  evaluate !(\%a|\%b)
+  0
+
+  evaluate !(\%a&\%b)
+  1
+
+  evaluate !(!(\%a&\%b))
+  0
+
+   Note the distinction between Prefix ! (invert truth value) and Suffix
+   ! (factorial). Also the distinction between Prefix ! and Prefix ~
+   (which inverts all the bits in its operand). Also note that prefix
+   operators (!, -, and ~) can not be adjacent unless you use parentheses
+   to separate them, as shown in the final example above.
+     _________________________________________________________________
+
+  7.23. Floating-Point Arithmetic
+
+   C-Kermit 7.0 adds limited support for floating-point numbers (numbers
+   that have fractional parts, like 3.141592653). This support is
+   provided through a small repertoire of functions and in Boolean
+   expressions that compare numbers, but does not apply to number parsing
+   in general, or to expression evaluation, array subscripts, the
+   INCREMENT and DECREMENT commands, or in any context other than those
+   listed in this section.
+
+   A floating point number has an optional sign (+ or -), followed by a
+   series of decimal digits containing either zero or one period (.)
+   character, which is the decimal point. The use of comma or any other
+   character besides period as a decimal point is not supported.
+   Scientific notation is not supported either. Examples of legal
+   floating-point numbers:
+
+  0                Integers can be used
+  1                Ditto
+  2.               A decimal point without decimal digits
+  3.0              A decimal point with decimal digits
+  3.141592653      Ditto
+ -4.0              A negative sign can be included
+ +5.0              A positive sign can be included
+
+   Examples of notations that are not accepted:
+
+  1,000,000        Separators can not be used
+  1.000.000        Ditto (or multiple decimal points)
+  6.022137E23      No scientific notation
+  6.62606868e-34   Ditto
+  12.5+6.25        No "bare" expressions
+
+   You can use IF FLOAT test a string or variable to see if it's in
+   acceptable floating-point format. Example:
+
+  ask \%f { Type a number: }
+  if not def \%f .\%f = 0.0
+  if not float \%f stop 1 Invalid floating-point number: "\%f"
+
+   C-Kermit's floating-point support, like its support for whole numbers
+   (integers), relies on the capabilities of the underlying computer.
+   Your computer has only a limited amount of precision for numbers,
+   depending on its architecture. Thus floating-point numbers that have
+   too many digits will not be accurate; adding a very small number to a
+   very large one might have no effect at all; and so on. For details,
+   read a text on numerical analysis. Example:
+
+  .\%a = 11111111111111111111  ; A long number
+  .\%b = 22222222222222222222  ; Another one
+  echo \ffpadd(\%a,\%b)        ; Add them - the result should be all 3's
+  33333333333333330000.0       ; See the result
+
+   In this example, the computer has 16 digits of precision; after that,
+   the (low-order) digits are set to 0, since the computer doesn't know
+   what they really are. In fact, the computer returns random digits, but
+   Kermit sets all digits beyond the computer's precision to 0.
+
+   C-Kermit's floating-point functions have names of the form
+   "\ffpxxx(args)" ("\f" for function, "fp" for floating-point), where
+   "xxx" is replaced by the name of the function, such as "sqrt", and
+   "args" is the argument list, consisting of one or two floating-point
+   numbers (depending on the function), and an optional "d" argument that
+   says now many decimal places should be shown in the result. Example:
+
+  \ffpdiv(10,3,1) returns "3.3"
+  \ffpdiv(10,3,2) returns "3.33"
+  \ffpdiv(10,3,3) returns "3.333"
+
+   and so on, up to the precision of the computer. If the decimal-places
+   argument is less than zero, the fractional part of the result is
+   truncated:
+
+  \ffpdiv(10,3,-1) returns "3".
+
+   If the decimal-places argument is 0, or is omitted, C-Kermit returns
+   as many decimal places as are meaningful in the computer's
+   floating-point precision, truncating any extraneous trailing 0's:
+
+  \ffpdiv(10,8) returns "1.25".
+  \ffpdiv(10,4) returns "2.5".
+  \ffpdiv(10,2) returns "5.0".
+  \ffpdiv(10,3) returns "3.333333333333333" (for 16-digit precision).
+
+   There is no way to request that a floating-point function return a
+   decimal point but no decimal places. However, this is easy enough to
+   accomplish in other ways, for example by supplying it outside the
+   function call:
+
+  echo \ffpadd(\%a,\%b,-1).
+
+   Kermit's floating-point functions always round the result for the
+   requested number of decimal places when the "d" argument is given and
+   has a value greater than 0 (see the description of \ffpround() just
+   below).
+
+   Floating-point arguments can be constants in floating-point format or
+   variables whose values are floating-point numbers. If a floating-point
+   argument is omitted, or is a variable with no value, 0.0 is supplied
+   automatically. Example:
+
+  def \%x 999.999
+  undef \%y
+  echo \ffpmin(\%x,\%y)
+  0.0
+
+   Or equivalently:
+
+  echo \ffpmin(999.999)
+  0.0
+
+   The floating-point functions are:
+
+   \ffpround(f1,d)
+          Returns f1 rounded to d decimal places. For this function only,
+          d = 0 (or d omitted) has a special meaning: return the integer
+          part of f1 rounded according to the fractional part. Examples:
+
+  \ffpround(2.74653,-1) returns "2" (fraction truncated, no rounding).
+  \ffpround(2.74653,0)  returns "3" (integer part is rounded).
+  \ffpround(2.74653)    returns "3" (d omitted same as d = 0).
+  \ffpround(2.74653,1)  returns "2.7".
+  \ffpround(2.74653,2)  returns "2.75".
+  \ffpround(2.74653,3)  returns "2.747".
+  \ffpround(2.74653,4)  returns "2.7465", etc.
+
+   \ffpadd(f1,f2,d)
+          Returns the sum of f1 and f2.
+
+   \ffpsubtract(f1,f2,d)
+          Subtracts f2 from f1 and returns the result.
+
+   \ffpmultiply(f1,f2,d)
+          Returns the product of f1 and f2.
+
+   \ffpdivide(f1,f2,d)
+          If f2 is not 0, divides f1 by f2 and returns the quotient.
+          If f2 is 0, a DIVIDE_BY_ZERO error occurs.
+
+   \ffpraise(f1,f2,d)
+          If f1 = 0 and f2 <= 0, or if f1 < 0 and f2 has a fractional
+          part, an ARG_OUT_OF_RANGE error occurs; otherwise f1 raised to
+          the f2 power is returned.
+
+   \ffpsqrt(f1,d)
+          If f1 >= 0, returns the square root of f1; otherwise
+          ARG_OUT_OF_RANGE.
+
+   \ffpabsolute(f1,d)
+          Returns the absolute value of f1 (i.e. f1 without a sign). This
+          is the floating-point analog of \fabsolute(n1).
+
+   \ffpint(f1)
+          Returns the integer part of f1. Equivalent to \ffpround(f1,-1).
+
+   \ffpexp(f1,d)
+          The base of natural logarithms, e (2.718282...), raised to the
+          f1 power.
+
+   \ffplogn(f1,d)
+          The natural logarithm of f1 (the power to which e must be
+          raised to obtain f1).
+
+   \ffplog10(f1,d)
+          The base-10 logarithm of f1 (the power to which 10 must be
+          raised to obtain f1).
+
+   \ffpmodulus(f1,f2,d)
+          If f2 is not 0, the remainder after dividing f1 by f2.
+          If f2 is 0, a DIVIDE_BY_ZERO error occurs.
+          This is the floating-point analog of \fmod(n1,n2).
+
+   \ffpmaximum(f1,f2,d)
+          Returns the maximum of f1 and f2. This is the floating-point
+          analog of \fmax(n1,n2).
+
+   \ffpminimum(f1,f2,d)
+          Returns the minimum of f1 and f2. This is the floating-point
+          analog of \fmin(n1,n2).
+
+   \ffpsine(f1,d)
+          Returns the sine of f1 radians.
+
+   \ffpcosine(f1,d)
+          Returns the cosine of f1 radians.
+
+   \ffptangent(f1,d)
+          Returns the tangent of f1 radians.
+
+   Note that all of these functions can be used with integer arguments.
+   If you want an integer result, specify d = -1 (to truncate) or feed
+   the result to \ffpround(xxx,0) (to round).
+
+   Floating-point numbers (or variables or functions that return them)
+   can be used in Boolean expressions (see [622]Section 7.20.2) that
+   compare numbers:
+
+  = x y
+  != x y
+  < x y
+  > x y
+  <= x y
+  >= x y
+
+   In these examples, x and y can be either integers or floating-point
+   numbers in any combination. In an arithmetic comparison of an integer
+   and a floating-point number, the integer is converted to
+   floating-point before the comparison is made. Examples:
+
+  .\%t = 3.000000000
+  .\%f = 3.141592653
+  .\%i = 3
+
+  if > \%f \%i echo Pi is greater.
+  if = \%t \%i echo "\%i" = "\%t".
+
+   A floating-point number can also be used in:
+
+  IF number command
+
+   where the command is executed if the number is nonzero. If the number
+   is floating-point, the command is not executed if the number is 0.0,
+   and is executed otherwise.
+
+   Floating-point numbers can be sorted using ARRAY SORT /NUMERIC (see
+   [623]Section 7.10.5 ).
+
+   Two floating-point constants are provided:
+
+  \v(math_pi) = Pi (3.141592653...)
+  \v(math_e)  = e, the base of natural logarithms (2.71828...)
+
+   These are given to the computer's precision, e.g. 16 digits. This
+   number itself is available in a variable:
+
+   \v(math_precision)
+          How many significant digits in a floating-point number.
+     _________________________________________________________________
+
+  7.24. Tracing Script Execution
+
+   The TRACE command is handy for debugging scripts.
+
+   TRACE [ { /ON, /OFF } ] [ { ASSIGNMENTS, COMMAND-LEVEL, ALL } ]
+          Selects tracing of the given object.
+
+   Optional switches are /ON and /OFF. If no switch is given, /ON is
+   implied. The trace objects are ASSIGNMENTS, COMMAND-LEVEL, and ALL.
+   The default object is ALL, meaning to select all trace objects
+   (besides ALL). Thus TRACE by itself selects tracing of everything, as
+   does TRACE /ON, and TRACE /OFF turns off all tracing.
+
+   When tracing of ASSIGNMENTS is on, every time the value of any
+   user-defined variable or macro changes, C-Kermit prints one of the
+   following:
+
+   >>> name: "value"
+          The name of the variable or macro followed by the new value in
+          quotes. This includes implicit macro-parameter assignments
+          during macro invocation.
+
+   >>> name: (undef)
+          This indicates that the variable or macro has been undefined.
+
+   <<< name: "value"
+          For RETURN statements: the name of the macro and the return
+          value.
+
+   <<< name: (null)
+          For RETURN statements that include no value or an empty value.
+
+   When tracing of COMMAND-LEVEL is on, C-Kermit prints:
+
+   [n] +F: "name"
+          Whenever a command file is entered, where "n" is the command
+          level (0 = top); the name of the command file is shown in
+          quotes.
+
+   [n] +M: "name"
+          Whenever a macro is entered; "n" is the command level. The name
+          of the macro is shown in quotes.
+
+   [n] -F: "name"
+          Whenever a command file is reentered from below, when a macro
+          or command file that it has invoked has returned.
+
+   [n] -M: "name"
+          Whenever a macro is reentered from below.
+
+   For other debugging tools, see SHOW ARGS, SHOW STACK, SET TAKE, SET
+   MACRO, and of course, ECHO.
+     _________________________________________________________________
+
+  7.25. Compact Substring Notation
+
+   It is often desirable to extract a substring from a string which is
+   stored in a variable, and for this we have the \fsubstring() function,
+   which is used like this:
+
+  define \%a 1234567890
+  echo \fsubstring(\%a,3,4) ; substring from 3rd character length 4
+  3456
+
+   or like this with macro-named variables:
+
+  define string 1234567890
+  echo \fsubstring(\m(string),3,4)
+  3456
+
+   C-Kermit 7.0 adds a pair of alternative compact notations:
+
+\:(variablename[start:length])  <-- Substring of variable's value
+\s(macroname[start:length])     <-- Substring of macro's definition
+
+   These are exactly equivalent to using \fsubstring(), except more
+   compact to write and also faster since evaluation is in one step
+   instead of two.
+
+   The "\:()" notation can be used with any Kermit variable, that is,
+   almost anything that starts with a backslash:
+
+  \:(\%a[2:6])      <-- equivalent to \fsubstring(\%a,2,6)
+  \:(\&x[1][2:6])   <-- equivalent to \fsubstring(\&x[1],2,6)
+  \:(\m(foo)[2:6])  <-- equivalent to \fsubstring(\m(foo),2,6)
+  \:(\v(time)[2:6]) <-- equivalent to \fsubstring(\v(time),2,6)
+  \:(\$(TERM)[2:6]) <-- equivalent to \fsubstring(\$(TERM),2,6)
+  \:(ABCDEFGH[2:6]) <-- equivalent to \fsubstring(ABCDEFGH,2,6)
+
+   Whatever appears between the left parenthesis and the left bracket is
+   evaluated and then the indicated substring of the result is returned.
+
+   The "\s()" notation is the same, except after evaluating the variable,
+   the result is treated as a macro name and is looked up in the macro
+   table. Then the indicated substring of the macro definition is
+   returned. Example:
+
+  define testing abcdefghijklmnopqrstuvwxyz
+  define \%a testing
+
+  \s(testing[2:6])  -->  bcdefg
+  \:(testing[2:6])  -->  esting
+  \:(\%a[2:6])      -->  esting
+  \s(\%a[2:6])      -->  bcdefg
+
+   Note that the following two examples are equivalent:
+
+  \:(\m(foo)[2:6])
+  \s(foo[2:6])
+
+   The first number in the brackets is the 1-based starting position. If
+   it is omitted, or less than 1, it is treated as 1. If it is greater
+   than the length of the string, an empty string is returned.
+
+   The second number is the length of the desired substring. If the
+   second number is omitted, is less than 0, or would be past the end of
+   the string, then "through the end of the string" is assumed. If it is
+   0, the empty string is returned.
+
+   If the brackets are empty or omitted, the original string is returned.
+
+   The starting position and length need not be literal numbers; they can
+   also be variables, functions, arithmetic expressions, or even other
+   \s() or \:() quantities; anything that evaluates to a number, for
+   example:
+
+  \s(block[1025:\fhex2n(\s(block[\%b:\%n+4]))/2])
+
+   Syntactically, \m(name) and \s(name) differ only in that the sequence
+   [*] at the end of the name (where * is any sequence of 0 or more
+   characters) is treated as substring notation in \s(name), but is
+   considered part of the name in \m(name) (to see why, see [624]Section
+   7.10.9).
+     _________________________________________________________________
+
+  7.26. New WAIT Command Options
+
+   The WAIT command has been extended to allow waiting for different
+   kinds of things (formerly it only waited for modem signals). Now it
+   also can wait for file events.
+
+    7.26.1. Waiting for Modem Signals
+
+   The previous syntax:
+
+  WAIT time { CD, DSR, RTS, RI, ... }
+
+   has changed to:
+
+  WAIT time MODEM-SIGNALS { CD, DSR, RTS, RI, ... }
+
+   However, the previous syntax is still accepted. The behavior is the
+   same in either case.
+     _________________________________________________________________
+
+    7.26.2. Waiting for File Events
+
+   The new WAIT option:
+
+  WAIT time FILE { CREATION, DELETION, MODIFICATION } filename
+
+   lets you tell Kermit to wait the given amount of time (or until the
+   given time of day) for a file whose name is filename to be created,
+   deleted, or modified, respectively. The filename may not contain
+   wildcards. If the specified event does not occur within the time
+   limit, or if WAIT CANCELLATION is ON and you interrupt from the
+   keyboard before the time is up, the WAIT command fails. If the event
+   is MODIFICATION and the file does not exist, the command fails.
+   Otherwise, if the given event occurs within the time limit, the
+   command succeeds. Examples:
+
+   WAIT 600 FILE DELETION oofa.tmp
+          Wait up to 10 minutes for file oofa.tmp to disappear.
+
+   WAIT 23:59:59 FILE MOD orders.db
+          Wait until just before midnight for the orders.db file to be
+          changed.
+
+   Example: Suppose you want to have the current copy of /etc/motd on
+   your screen at all times, and you want to hear a bell whenever it
+   changes:
+
+  def \%f /etc/motd                      ; The file of interest.
+  while 1 {                              ; Loop forever...
+      cls                                ; Clear the screen.
+      echo \%f: \v(date) \v(time)...     ; Print 2-line heading...
+      echo
+      if ( not exist \%f ) {             ; If file doesn't exist,
+          echo \%f does not exist...     ; print message,
+          wait 600 file creat \%f        ; and wait for it to appear.
+          continue
+      }
+      beep                               ; Something new - beep.
+      type /head:\v(rows-2) \%f          ; Display the file
+      if fail exit 1 \%f: \ferrstring()  ; (checking for errors).
+      wait 999 file mod \%f              ; Wait for it to change.
+  }
+
+   This notices when the file is created, deleted, or modified, and acts
+   only then (or when you interrupt it with); the time shown in the
+   heading is the time of the most recent event (including when the
+   program started).
+
+   See [625]Section 1.10, where the \v(kbchar) variable is explained.
+   This lets you modify a loop like the one above to also accept
+   single-character commands, which interrupt the WAIT, and dispatch
+   accordingly. For example:
+
+  wait 999 file mod \%f              ; Wait for the file to change.
+  if defined \v(kbchar) {            ; Interrupted from keyboard?
+      switch \v(kbchar) {            ; Handle the keystroke...
+        :q, exit                     ; Q to Quit
+        :h, echo blah blah, break    ; H for Help
+        :default, beep, continue     ; Anything else beep and ignore
+      }
+  }
+
+   This lets you write event-driven applications that wait for up to
+   three events at once: a file or modem event, a timeout, and a
+   keystroke.
+     _________________________________________________________________
+
+  7.27. Relaxed FOR and SWITCH Syntax
+
+   For consistency with the extended IF and WHILE syntax, the FOR and
+   SWITCH control lists may (but need not be) enclosed in parentheses:
+
+  FOR ( \%i 1 \%n 1 ) { command-list... }
+  SWITCH ( \%c ) { command-list... }
+
+   In the FOR command, the increment item can be omitted if the control
+   list is enclosed in parentheses, in which case the increment defaults
+   appropriately to 1 or -1, depending on the values of the first two
+   variables.
+
+   As with IF, the parentheses around the FOR-command control list must
+   be set off by spaces (in the SWITCH command, the spaces are not
+   required since the SWITCH expression is a single arithmetic
+   expression).
+
+   Also, outer braces around the command list are supplied automatically
+   if you omit them, e.g.:
+
+  FOR ( \%i 1 %n 1 ) echo \%i
+     _________________________________________________________________
+
+  8. USING OTHER FILE TRANSFER PROTOCOLS
+
+   In C-Kermit 7.0, alternative protocols can be selected using switches.
+   Switches are described in [626]Section 1.5; the use of
+   protocol-selection switches is described in [627]Section 4.7.1.
+   Example:
+
+  send /binary /protocol:zmodem x.tar.gz
+
+   Note that file transfer recovery works only with Kermit and Zmodem
+   protocols. With Zmodem, recovery can be initiated only by the sender.
+
+   Only pre-1988 versions of the publicly-distributed sz/rz programs use
+   Standard I/O; those released later than that do not use Standard I/O
+   and therefore do not work with REDIRECT. However, Omen Technology does
+   offer an up-to-date redirectable version called crzsz, which must be
+   licensed for use:
+
+     "Unix Crz and Csz support XMODEM, YMODEM, and ZMODEM transfers when
+     called by dial-out programs such as Kermit and certain versions of
+     cu(1). They are clients designed for this use.
+
+     "Crz and Csz are Copyrighted shareware programs. Use of these
+     programs beyond a brief evaluation period requires registration.
+     Please print the "mailer.rz" file, fill out the form and return
+     same with your registration."
+
+   To use the crzsz programs as your external XYZMODEM programs in
+   C-Kermit, follow the instructions in the book, but put a "c" before
+   each command, e.g.:
+
+  set protocol zmodem {csz %s} {csz -a %s} crz crz crz crz
+
+   To use Zmodem protocol over Telnet or other non-transparent
+   connections, you might need to add the -e (Escape) option:
+
+  set protocol zmodem {csz -e %s} {csz -e -a %s} crz crz crz crz
+     _________________________________________________________________
+
+  9. COMMAND-LINE OPTIONS
+
+  9.0. Extended-Format Command-Line Options
+
+   Standard UNIX command line options are a single letter. C-Kermit has
+   run out of letters, so new options are in a new extended format:
+
+ --word[:arg]
+
+   where a keyword (rather than a single letter) specifies the function,
+   and if an argument is to be included, it is separated by a colon (or
+   equal sign). Most of the new extended-format command-line options are
+   only for use with the Internet Kermit Service Daemon; see the
+   [628]IKSD Administration Guide for details. However, several of them
+   are also general in nature:
+
+   --nointerrupts
+          Disables keyboard interrupts that are normally enabled, which
+          are usually Ctrl-C (to interrupt a command) and Ctrl-Z (UNIX
+          only, to suspend C-Kermit).
+
+   --help
+          Lists the extended command-line options that are available in
+          your version of C-Kermit. If any options seem to be missing,
+          that is because your copy of C-Kermit was built with
+          compile-time options to deselect them.
+
+   --helpfile:filename
+          Specifies the name of a file to be displayed if the user types
+          HELP (not followed by a specific command or topic), in place of
+          the built-in top-level help text. The file need not fit on one
+          screen; more-prompting is used if the file is more than one
+          screen long if COMMAND MORE-PROMPTING is ON, as it is by
+          default.
+
+   --bannerfile:filename
+          The name of a file containing a message to be printed after the
+          user logs in, in place of the normal message (Copyright notice,
+          "Type HELP or ? for help", "Default transfer mode is...", etc).
+
+   --cdmessage:{on,off,0,1,2}
+          For use in the Server-Side Server configuration; whenever the
+          client tells the server to change directory, the server sends
+          the contents of a "read me" file to the client's screen. This
+          feature is On by default, and operates only in client/server
+          mode when ON or 1. If set to 2 or higher, it also operates when
+          the CD command is given at the IKSD> prompt. Synonym: --cdmsg.
+
+   --cdfile:filename
+          When cdmessage is on, this is the name of the "read me" file to
+          be sent. Normally you would specify a relative (not absolute)
+          name, since the file is opened using the literal name you
+          specified, after changing to the new directory. Example:
+
+  --cdfile:READ.ME
+
+          You can also give a list of up to 8 filenames by (a) enclosing
+          each filename in braces, and (b) enclosing the entire list in
+          braces. Example:
+          --cdfile:{{./.readme}{READ.ME}{aaareadme.txt}{README}{read-this
+          -first}} When a list is given, it is searched from left to
+          right and the first file found is displayed. The default list
+          for UNIX is:
+
+  {{./.readme}{README.TXT}{READ.ME}}
+     _________________________________________________________________
+
+  9.1. Command Line Personalities
+
+   Beginning in version 7.0, if the C-Kermit binary is renamed to
+   "telnet" (or TELNET.EXE, telnet.pr, etc, depending on the platform),
+   it accepts the Telnet command line:
+
+  telnet [ host [ port ] ]
+
+   In Unix, you can achieve the same effect with a symlink:
+
+  cd /usr/bin
+  mv telnet oldtelnet
+  ln -ls /usr/local/bin/kermit telnet
+
+   When installed in this manner, C-Kermit always reads its
+   initialization file. If no host (and therefore no port) is given,
+   C-Kermit starts in interactive prompting mode. If a host is given as
+   the first command-line argument, C-Kermit makes a connection to it.
+   The host argument can be an IP host name or address, or the name of a
+   TCP/IP entry in your C-Kermit network directory.
+
+   If a port is given, it is used. If a port is not given, then if the
+   hostname was found in your network directory and port was also listed
+   there, then that port is used. Otherwise port 23 (the Telnet port) is
+   used.
+
+   When C-Kermit is called "telnet" and it is invoked with a hostname on
+   the command line, it exits automatically when the connection is
+   closed. While the connection is open, however, you may escape back and
+   forth as many times as you like, transfer files, etc.
+
+   An rlogin personality is also available, but it is less useful, at
+   least in UNIX and VMS, where the Rlogin TCP port is privileged.
+
+   The new variable \v(name) indicates the name with which C-Kermit was
+   invoked ("kermit", "wermit", "k95", "telnet", etc).
+     _________________________________________________________________
+
+  9.2. Built-in Help for Command Line Options
+
+   "kermit -h", given from the system prompt, lists as many command-line
+   options as will fit on a standard 24x80 screen. For more comprehensive
+   help, use the interactive HELP OPTIONS command that was added in
+   C-Kermit 7.0:
+
+   HELP OPTIONS
+   Explains how command-line options work, their syntax, etc.
+
+   HELP OPTIONS ALL
+   Lists all command-line options and gives brief help about each one.
+
+   HELP OPTION x
+   Gives brief help about option "x".
+
+   HELP EXTENDED-OPTIONS
+   Lists the available extended-format command-line options.
+
+   HELP EXTENDED-OPTION xxx
+   Gives help for the specified extended option.
+     _________________________________________________________________
+
+  9.3. New Command-Line Options
+
+   Command-line options added since C-Kermit 6.0 are:
+
+   +
+          (plus sign by itself): The next argument is the name of a
+          script to execute; all subsequent arguments are ignored by
+          C-Kermit itself, but passed to the script as top-level copies
+          of \%1, \%2, etc; the \&_[] is also set accordingly. \%0 and
+          \&_[0] become the name of the script file, rather than the
+          pathname of the C-Kermit program, which is its normal value.
+          Primarily for use in the top line of "Kerbang" scripts in UNIX
+          (see [629]Section 7.19). Example from UNIX command line:
+
+  $ kermit [ regular kermit args ] + filename
+
+          Sample first line of Kerbang script:
+
+  #!/usr/local/bin/kermit +
+
+   --
+          (two hyphens surrounded by whitespace) Equivalent to "=", for
+          compatibility with UNIX getopt(1,3).
+
+   -G
+          GET (like -g), but send the incoming file to standard output.
+          Example: "kermit -G oofa.txt | lpr" retrieves a file from your
+          local computer (providing it is running a Kermit program that
+          supports the autodownload feature and has it enabled) and
+          prints it.
+
+   -O
+          equivalent to -x (start up in server mode), but exits after the
+          first client command has been executed (mnemonic: O = Only
+          One). This one is handy replacing "kermit -x" in the
+          "automatically start Kermit on the other end" string:
+
+  set protocol kermit {kermit -ir} {kermit -r} {kermit -x}
+
+          since -x leaves the remote Kermit in server mode after the
+          transfer, which can be confusing, whereas -O makes it go away
+          automatically after the transfer.
+
+   -L
+          Recursive, when used in combination with -s (mnemonic: L =
+          Levels). In UNIX or other environments where the shell expands
+          wildcards itself, the -s argument, if it contains wildcards,
+          must be quoted to prevent this, e.g.:
+
+  kermit -L -s "*.c"
+
+          In UNIX only, "kermit -L -s ." means to send the current
+          directory tree. See [630]Sections 4.10 and [631]4.11 about
+          recursive file transfer.
+
+   -V
+          Equivalent to SET FILE PATTERNS OFF ([632]Section 4.3) and SET
+          TRANSFER MODE MANUAL. In other words, take the FILE TYPE
+          setting literally. For example, "kermit -VT oofa.bin" means
+          send the file in Text mode, no matter what its name is and no
+          matter whether a kindred spirit is recognized at the other end
+          of the connection.
+
+   -0
+          (digit zero) means "be 100% transparent in CONNECT mode". This
+          is equivalent to the following series of commands: SET PARITY
+          NONE, SET COMMAND BYTESIZE 8, SET TERMINAL BYTESIZE 8, SET FLOW
+          NONE, SET TERM ESCAPE DISABLED, SET TERM CHAR TRANSPARENT, SET
+          TERM AUTODOWNLOAD OFF, SET TERM APC OFF, SET TELOPT KERMIT
+          REFUSE REFUSE.
+     _________________________________________________________________
+
+  10. C-KERMIT AND G-KERMIT
+
+   Every multifunctioned and long-lived software program grows in
+   complexity and size over time to meet the needs and requests of its
+   users and the demands of the underlying technology as it changes.
+
+   Eventually users begin to notice how big the application has grown,
+   how much disk space it occupies, how long it takes to load, and they
+   start to long for the good old days when it was lean and mean. Not
+   long after that they begin asking for a "light" version that only does
+   the basics with no frills.
+
+   And so it is with C-Kermit. A "light" version of Kermit was released
+   (for UNIX only) in December 1999 under the GNU General Public License;
+   thus it is called G-Kermit (for GNU Kermit). All it does is send and
+   receive files, period. You can find it at:
+
+  [633]http://www.columbia.edu/kermit/gkermit.html
+
+   Where the C-Kermit 7.0 binary might be anywhere from 1 to 3 million
+   bytes in size, the G-Kermit binary ranges from 30K to 100K, depending
+   on the underlying architecture (RISC vs CISC, etc).
+
+   G-Kermit and C-Kermit may reside side-by-side on the same computer.
+   G-Kermit does not make connections; it does not have a script
+   language; it does not translate character sets. G-Kermit may be used
+   instead of C-Kermit when:
+
+     * It is on the remote end.
+     * Files are to be transferred in binary mode or in text mode without
+       character-set translation.
+     * File timestamps don't need to be preserved.
+
+   In such cases G-Kermit might be preferred since it generally starts up
+   faster, and yet transfers files just as fast on most (but not
+   necessarily all) kinds of connections; for example, it supports
+   streaming ([634]Section 4.20).
+
+   G-Kermit is also handy for bootstrapping. It is easier to load on a
+   new computer than C-Kermit -- it fits on a floppy diskette with plenty
+   of room to spare. Thus if you have (say) an old PC running (say) SCO
+   Xenix and no network connection, you can download the Xenix version of
+   G-Kermit to (say) a DOS or Windows PC, copy it to diskette, read the
+   diskette on Xenix with "dosread", and then use G-Kermit to receive
+   C-Kermit (which does not fit on a diskette). If diskettes aren't an
+   option, other bootstrapping methods are possible too -- see the
+   [635]G-Kermit web page for details.
+     _________________________________________________________________
+
+III. APPENDICES
+
+  III.1. Character Set Tables
+
+    III.1.1. The Hewlett Packard Roman8 Character Set
+
+dec col/row oct hex  description
+160  10/00  240  A0  (Undefined)
+161  10/01  241  A1  A grave
+162  10/02  242  A2  A circumflex
+163  10/03  243  A3  E grave
+164  10/04  244  A4  E circumflex
+165  10/05  245  A5  E diaeresis
+166  10/06  246  A6  I circumflex
+167  10/07  247  A7  I diaeresis
+168  10/08  250  A8  Acute accent
+169  10/09  251  A9  Grave accent
+170  10/10  252  AA  Circumflex accent
+171  10/11  253  AB  Diaeresis
+172  10/12  254  AC  Tilde accent
+173  10/13  255  AD  U grave
+174  10/14  256  AE  U circumflex
+175  10/15  257  AF  Lira symbol
+176  11/00  260  B0  Top bar (macron)
+177  11/01  261  B1  Y acute
+178  11/02  262  B2  y acute
+179  11/03  263  B3  Degree Sign
+180  11/04  264  B4  C cedilla
+181  11/05  265  B5  c cedilla
+182  11/06  266  B6  N tilde
+183  11/07  267  B7  n tilde
+184  11/08  270  B8  Inverted exclamation mark
+185  11/09  271  B9  Inverted question mark
+186  11/10  272  BA  Currency symbol
+187  11/11  273  BB  Pound sterling symbol
+188  11/12  274  BC  Yen symbol
+189  11/13  275  BD  Paragraph
+190  11/14  276  BE  Florin (Guilder) symbol
+191  11/15  277  BF  Cent symbol
+192  12/00  300  C0  a circumflex
+193  12/01  301  C1  e circumflex
+194  12/02  302  C2  o circumflex
+195  12/03  303  C3  u circumflex
+196  12/04  304  C4  a acute
+197  12/05  305  C5  e acute
+198  12/06  306  C6  o acute
+199  12/07  307  C7  u acute
+200  12/08  310  C8  a grave
+201  12/09  311  C9  e grave
+202  12/10  312  CA  o grave
+203  12/11  313  CB  u grave
+204  12/12  314  CC  a diaeresis
+205  12/13  315  CD  e diaeresis
+206  12/14  316  CE  o diaeresis
+207  12/15  317  CF  u diaeresis
+208  13/00  320  D0  A ring
+209  13/01  321  D1  i circumflex
+210  13/02  322  D2  O with stroke
+211  13/03  323  D3  AE digraph
+212  13/04  324  D4  a ring
+213  13/05  325  D5  i acute
+214  13/06  326  D6  o with stroke
+215  13/07  327  D7  ae digraph
+216  13/08  330  D8  A diaeresis
+217  13/09  331  D9  i grave
+218  13/10  332  DA  O diaeresis
+219  13/11  333  DB  U diaeresis
+220  13/12  334  DC  E acute
+221  13/13  335  DD  i diaeresis
+222  13/14  336  DE  German sharp s
+223  13/15  337  DF  O circumflex
+224  14/00  340  E0  A acute
+225  14/01  341  E1  A tilde
+226  14/02  342  E2  a tilde
+227  14/03  343  E3  Icelandic Eth
+228  14/04  344  E4  Icelandic eth
+229  14/05  345  E5  I acute
+230  14/06  346  E6  I grave
+231  14/07  347  E7  O acute
+232  14/08  350  E8  O grave
+233  14/09  351  E9  O tilde
+234  14/10  352  EA  o tilde
+235  14/11  353  EB  S caron
+236  14/12  354  EC  s caron
+237  14/13  355  ED  U acute
+238  14/14  356  EE  Y diaeresis
+239  14/15  357  EF  y diaeresis
+240  15/00  360  F0  Icelandic Thorn
+241  15/01  361  F1  Icelandic thorn
+242  15/02  362  F2  Middle dot
+243  15/03  363  F3  Greek mu
+244  15/04  364  F4  Pilcrow sign
+245  15/05  365  F5  Fraction 3/4
+246  15/06  366  F6  Long dash, horizontal bar
+247  15/07  367  F7  Fraction 1/4
+248  15/08  370  F8  Fraction 1/2
+249  15/09  371  F9  Feminine ordinal
+250  15/10  372  FA  Masculine ordinal
+251  15/11  373  FB  Left guillemot
+252  15/12  374  FC  Solid box
+253  15/13  375  FD  Right guillemot
+254  15/14  376  FE  Plus or minus sign
+255  15/15  377  FF  (Undefined)
+     _________________________________________________________________
+
+    III.1.2. Greek Character Sets
+
+    III.1.2.1. The ISO 8859-7 Latin / Greek Alphabet = ELOT 928
+
+dec col/row oct hex  description
+160  10/00  240  A0  No-break space
+161  10/01  241  A1  Left single quotation mark
+162  10/02  242  A2  right single quotation mark
+163  10/03  243  A3  Pound sign
+164  10/04  244  A4  (UNUSED)
+165  10/05  245  A5  (UNUSED)
+166  10/06  246  A6  Broken bar
+167  10/07  247  A7  Paragraph sign
+168  10/08  250  A8  Diaeresis (Dialytika)
+169  10/09  251  A9  Copyright sign
+170  10/10  252  AA  (UNUSED)
+171  10/11  253  AB  Left angle quotation
+172  10/12  254  AC  Not sign
+173  10/13  255  AD  Soft hyphen
+174  10/14  256  AE  (UNUSED)
+175  10/15  257  AF  Horizontal bar (Parenthetiki pavla)
+176  11/00  260  B0  Degree sign
+177  11/01  261  B1  Plus-minus sign
+178  11/02  262  B2  Superscript two
+179  11/03  263  B3  Superscript three
+180  11/04  264  B4  Accent (tonos)
+181  11/05  265  B5  Diaeresis and accent (Dialytika and Tonos)
+182  11/06  266  B6  Alpha with accent
+183  11/07  267  B7  Middle dot (Ano Teleia)
+184  11/08  270  B8  Epsilon with accent
+185  11/09  271  B9  Eta with accent
+186  11/10  272  BA  Iota with accent
+187  11/11  273  BB  Right angle quotation
+188  11/12  274  BC  Omicron with accent
+189  11/13  275  BD  One half
+190  11/14  276  BE  Upsilon with accent
+191  11/15  277  BF  Omega with accent
+192  12/00  300  C0  iota with diaeresis and accent
+193  12/01  301  C1  Alpha
+194  12/02  302  C2  Beta
+195  12/03  303  C3  Gamma
+196  12/04  304  C4  Delta
+197  12/05  305  C5  Epsilon
+198  12/06  306  C6  Zeta
+199  12/07  307  C7  Eta
+200  12/08  310  C8  Theta
+201  12/09  311  C9  Iota
+202  12/10  312  CA  Kappa
+203  12/11  313  CB  Lamda
+204  12/12  314  CC  Mu
+205  12/13  315  CD  Nu
+206  12/14  316  CE  Ksi
+207  12/15  317  CF  Omicron
+208  13/00  320  D0  Pi
+209  13/01  321  D1  Rho
+210  13/02  322  D2  (UNUSED)
+211  13/03  323  D3  Sigma
+212  13/04  324  D4  Tau
+213  13/05  325  D5  Upsilon
+214  13/06  326  D6  Phi
+215  13/07  327  D7  Khi
+216  13/08  330  D8  Psi
+217  13/09  331  D9  Omega
+218  13/10  332  DA  Iota with diaeresis
+219  13/11  333  DB  Upsilon with diaeresis
+220  13/12  334  DC  alpha with accent
+221  13/13  335  DD  epsilon with accent
+222  13/14  336  DE  eta with accent
+223  13/15  337  DF  iota with accent
+224  14/00  340  E0  upsilon with diaeresis and accent
+225  14/01  341  E1  alpha
+226  14/02  342  E2  beta
+227  14/03  343  E3  gamma
+228  14/04  344  E4  delta
+229  14/05  345  E5  epsilon
+230  14/06  346  E6  zeta
+231  14/07  347  E7  eta
+232  14/08  350  E8  theta
+233  14/09  351  E9  iota
+234  14/10  352  EA  kappa
+235  14/11  353  EB  lamda
+236  14/12  354  EC  mu
+237  14/13  355  ED  nu
+238  14/14  356  EE  ksi
+239  14/15  357  EF  omicron
+240  15/00  360  F0  pi
+241  15/01  361  F1  rho
+242  15/02  362  F2  terminal sigma
+243  15/03  363  F3  sigma
+244  15/04  364  F4  tau
+245  15/05  365  F5  upsilon
+246  15/06  366  F6  phi
+247  15/07  367  F7  khi
+248  15/08  370  F8  psi
+249  15/09  371  F9  omega
+250  15/10  372  FA  iota with diaeresis
+251  15/11  373  FB  upsilon with diaeresis
+252  15/12  374  FC  omicron with diaeresis
+253  15/13  375  FD  upsilon with accent
+254  15/14  376  FE  omega with accent
+255  15/15  377  FF  (UNUSED)
+     _________________________________________________________________
+
+    III.1.2.2. The ELOT 927 Character Set
+
+dec col/row oct hex  description
+ 32  02/00   40  20  SPACE
+ 33  02/01   41  21  EXCLAMATION MARK
+ 34  02/02   42  22  QUOTATION MARK
+ 35  02/03   43  23  NUMBER SIGN
+ 36  02/04   44  24  DOLLAR SIGN
+ 37  02/05   45  25  PERCENT SIGN
+ 38  02/06   46  26  AMPERSAND
+ 39  02/07   47  27  APOSTROPHE
+ 40  02/08   50  28  LEFT PARENTHESIS
+ 41  02/09   51  29  RIGHT PARENTHESIS
+ 42  02/10   52  2A  ASTERISK
+ 43  02/11   53  2B  PLUS SIGN
+ 44  02/12   54  2C  COMMA
+ 45  02/13   55  2D  HYPHEN, MINUS SIGN
+ 46  02/14   56  2E  PERIOD, FULL STOP
+ 47  02/15   57  2F  SOLIDUS, SLASH
+ 48  03/00   60  30  DIGIT ZERO
+ 49  03/01   61  31  DIGIT ONE
+ 50  03/02   62  32  DIGIT TWO
+ 51  03/03   63  33  DIGIT THREE
+ 52  03/04   64  34  DIGIT FOUR
+ 53  03/05   65  35  DIGIT FIVE
+ 54  03/06   66  36  DIGIT SIX
+ 55  03/07   67  37  DIGIT SEVEN
+ 56  03/08   70  38  DIGIT EIGHT
+ 57  03/09   71  39  DIGIT NINE
+ 58  03/10   72  3A  COLON
+ 59  03/11   73  3B  SEMICOLON
+ 60  03/12   74  3C  LESS-THAN SIGN, LEFT ANGLE BRACKET
+ 61  03/13   75  3D  EQUALS SIGN
+ 62  03/14   76  3E  GREATER-THAN SIGN, RIGHT ANGLE BRACKET
+ 63  03/15   77  3F  QUESTION MARK
+ 64  04/00  100  40  COMMERCIAL AT SIGN
+ 65  04/01  101  41  CAPITAL LETTER A
+ 66  04/02  102  42  CAPITAL LETTER B
+ 67  04/03  103  43  CAPITAL LETTER C
+ 68  04/04  104  44  CAPITAL LETTER D
+ 69  04/05  105  45  CAPITAL LETTER E
+ 70  04/06  106  46  CAPITAL LETTER F
+ 71  04/07  107  47  CAPITAL LETTER G
+ 72  04/08  110  48  CAPITAL LETTER H
+ 73  04/09  111  49  CAPITAL LETTER I
+ 74  04/10  112  4A  CAPITAL LETTER J
+ 75  04/11  113  4B  CAPITAL LETTER K
+ 76  04/12  114  4C  CAPITAL LETTER L
+ 77  04/13  115  4D  CAPITAL LETTER M
+ 78  04/14  116  4E  CAPITAL LETTER N
+ 79  04/15  117  4F  CAPITAL LETTER O
+ 80  05/00  120  50  CAPITAL LETTER P
+ 81  05/01  121  51  CAPITAL LETTER Q
+ 82  05/02  122  52  CAPITAL LETTER R
+ 83  05/03  123  53  CAPITAL LETTER S
+ 84  05/04  124  54  CAPITAL LETTER T
+ 85  05/05  125  55  CAPITAL LETTER U
+ 86  05/06  126  56  CAPITAL LETTER V
+ 87  05/07  127  57  CAPITAL LETTER W
+ 88  05/08  130  58  CAPITAL LETTER X
+ 89  05/09  131  59  CAPITAL LETTER Y
+ 90  05/10  132  5A  CAPITAL LETTER Z
+ 91  05/11  133  5B  LEFT SQUARE BRACKET
+ 92  05/12  134  5C  REVERSE SOLIDUS, BACKSLASH
+ 93  05/13  135  5D  RIGHT SQUARE BRACKET
+ 94  05/14  136  5E  CIRCUMFLEX ACCENT
+ 95  05/15  137  5F  UNDERSCORE
+ 96  06/00  140  60  ACCENT GRAVE
+ 97  06/01  141  61  GREEK LETTER ALPHA
+ 98  06/02  142  62  GREEK LETTER BETA
+ 99  06/03  143  63  GREEK LETTER GAMMA
+100  06/04  144  64  GREEK LETTER DELTA
+101  06/05  145  65  GREEK LETTER EPSILON
+102  06/06  146  66  GREEK LETTER ZETA
+103  06/07  147  67  GREEK LETTER ETA
+104  06/08  150  68  GREEK LETTER THETA
+105  06/09  151  69  GREEK LETTER IOTA
+106  06/10  152  6A  GREEK LETTER KAPPA
+107  06/11  153  6B  GREEK LETTER LAMDA
+108  06/12  154  6C  GREEK LETTER MU
+109  06/13  155  6D  GREEK LETTER NU
+110  06/14  156  6E  GREEK LETTER KSI
+111  06/15  157  6F  GREEK LETTER OMICRON
+112  07/00  160  70  GREEK LETTER PI
+113  07/01  161  71  GREEK LETTER RHO
+114  07/02  162  72  GREEK LETTER SIGMA
+115  07/03  163  73  GREEK LETTER TAU
+116  07/04  164  74  GREEK LETTER UPSILON
+117  07/05  165  75  GREEK LETTER FI
+118  07/06  166  76  GREEK LETTER XI
+119  07/07  167  77  GREEK LETTER PSI
+120  07/08  170  78  GREEK LETTER OMEGA
+121  07/09  171  79  SPACE
+122  07/10  172  7A  SPACE
+123  07/11  173  7B  LEFT CURLY BRACKET, LEFT BRACE
+124  07/12  174  7C  VERTICAL LINE, VERTICAL BAR
+125  07/13  175  7D  RIGHT CURLY BRACKET, RIGHT BRACE
+126  07/14  176  7E  TILDE
+127  07/15  177  7F  RUBOUT, DELETE
+     _________________________________________________________________
+
+    III.1.2.3. PC Code Page 869
+
+   (to be filled in...)
+     _________________________________________________________________
+
+    III.2. Updated Country Codes
+
+   Date: Mon, 7 Apr 1997 23:23:49 EDT
+   From: Dave Leibold <dleibold@else.net>
+   Newsgroups: comp.dcom.telecom
+   Subject: Ex-USSR Country Codes Profile
+   Organization: TELECOM Digest
+
+   Ex-USSR Country Codes Profile
+   4 April 1997
+
+   Below is a summary of the country codes that have formed in the wake
+   of the USSR dissolution, along with some updated findings and reports.
+   Additional or corrected information on any of these nations would be
+   welcome (c/o dleibold@else.net).
+     * Kyrgyz Republic country code 996 will take effect, at least in
+       Canada, effective 1 May 1997, according to CRTC Telecom Order
+       97-464, based on Stentor Tariff Notice 433. There is no indication
+       whether there will be a permissive dialing period involved or for
+       how long such a permissive operation would remain.
+     * Country code 992 was reported as a recent assignment for
+       Tajikistan, which will be moving from country code 7 at some
+       unknown time.
+     * Uzbekistan has its own country code assignment, but I have no
+       information if this is in service yet or what implementation dates
+       have been set.
+     * Kazakstan does not have a known separate country code assignment
+       at present. It remains in country code 7 for the time being.
+     * Russia seems destined to keep country code 7.
+     * Recent news reports speak of some agreements forming between
+       Russia and Belarus. While there is no outright reunification yet,
+       there is expected to be much closer ties between the two nations.
+       Whether this will lead to a reunification of telephone codes
+       remains to be seen.
+
+   In the table, "Effective" means the date at which the country code
+   began service (which could vary according to the nation). "Mandatory"
+   means the date at which the country code 7 is invalid for calls to
+   that nation. There are a number of question marks since exact dates
+   have not been collected in all cases.
+
+CC  Nation            Effective     Mandatory    Notes
+
+370 Lithuania         1993?         ???          Announced Jan 1993
+371 Latvia            1993?         ???
+372 Estonia           1 Feb 1993?   March 1993?
+373 Moldova           1993?         ???          Announced Jan 1993
+374 Armenia           1 May 1995    1 July 1995  Announced Jan 1995 (ITU)
+375 Belarus           16 Apr 1995   1997?
+380 Ukraine           16 Apr 1995   Oct 1995?
+7   Kazakstan         (no known changes)
+7   Russia            (presumably not changing)
+992 Tajikistan        ???           ???          Announced 1996-7?
+993 Turkmenistan      3 Jan 1997    3 Apr 1997   Canada as of 29 Nov 1996
+994 Azerbaijan        Sept 1994?    ???          Announced 1992
+995 Georgia           1994?         ???          ref: Telecom Digest Oct 1994
+996 Kyrgyz Republic   1 May 1997    ???          ref: Stentor Canada/CRTC
+998 Uzbekistan        ???           ???          Announced 1996? (ITU)
+
+   Details courtesy Toby Nixon, ITU, Stentor (Canada), CRTC (Canada),
+   TELECOM Digest (including information collected for the country code
+   listings).
+     _________________________________________________________________
+
+IV. ERRATA & CORRIGENDA
+
+   The following errors in [636]Using C-Kermit, Second Edition, first
+   printing, have been noted.
+
+   First, some missing acknowledgements for C-Kermit 6.0: JE Jones of
+   Microware for help with OS-9, Nigel Roles for his help with Plan 9,
+   Lucas Hart for help with VMS and Digital UNIX, Igor Kovalenko for his
+   help with QNX. And later, to Susan Kleinmann for her help with Debian
+   Linux packaging; Patrick Volkerding for his help with Slackware Linux
+   packaging; Jim Knoble for his help with Red Hat Linux packaging; and
+   to dozens of others for sending individual C-Kermit binaries for
+   varied and diverse platforms.
+
+   Thanks to James Spath for both binaries and reporting many of the
+   typos noted below. Also to Dat Thuc Nguyen for spotting several typos.
+
+PAGE    REMARKS
+COVER   "COS" is a misprint.  There is no COS.  Pretend it says "SCO" or "VOS".
+        (This is fixed in the second printing.)
+ xxi    Second line: Fred Smith's affiliation should be Computrition.
+ 83     Change "commands other" to "commands as other" (1st paragraph)
+ 87     Change "The the" to "The" (2nd paragraph)
+ 92     "set modem-type user-defined supra" should be "set modem type ..."
+ 95     Change "VI" to "vi" (1st paragraph)
+ 96     Change "it it" to "it is" (1st paragraph)
+ 97     Change "advantage a literal" to "advantage of a literal" (2nd
+        paragraph)
+102     The call-waiting example would be better as SET DIAL PREFIX *70W
+        (rather than "*70,") because the former will not cause an incorrect
+        call to be placed with pulse dialing.
+123     Third paragraph from bottom: "..otherwise if a your local username.."
+        should be "..otherwise your local username..".
+160     Delete the "it" between "and" and "to" (2nd paragraph)
+185     In "When TRANSFER DISPLAY is OFF, C-Kermit skips the display...",
+        "OFF" should be "NONE".
+187     The last paragraph says the "A command" is ignored, should be "S".
+194     Change "it known" to "it is known" (4th paragraph).
+235     In C-Kermit 7.0, the syntax of the GET command changed.  MGET now
+        must be used to get a list of files and there is no more multiline
+        GET command.
+268     Last paragraph: "effect" should be "affect".
+275     In the SET PROTOCOL KERMIT description, the following sentence is
+        incorrect and should be removed: 'If you omit the commands, the
+        default ones are restored: "kermit -ir" and "kermit -r" respectively".
+        The correct information is given at the bottom of page 281.
+279     9th line.  The decimal value of ST is 156, not 155.
+295     In the stepping stones, skip ahead to Chapter 17 on p. 327.
+298     Table 16-2, Portuguese entry.  Column 4/00 should show section sign,
+        not acute accent.
+316     Other languages written in the Hebrew alphabet include Karaim (a Turkic
+        language spoken in Lithuania and Poland), Judeo-Kurdish, and Judeo-
+        Georgian.
+332     UNDEFINE definition, change "This just" to "This is just".
+344     It might be necessary to set the modem's pulse generation rate when
+        sending numeric pages; most Hayes compatible modems use the S11
+        register for this.
+350     Delete "is" from between "It" and "ceases" (4th paragraph)
+351     Top - both occurrences of "print \%a" should be "echo \%a".
+364     \v(input) and \v(query) out of alphabetical order.
+378     In the MYSEND macro, "if not \m(rc) goto bad" should be:
+        "if \m(rc) goto bad" (remove the "not").
+382-383 It should be stated that the loop control variable must be of the \%a
+        type, or else an array element; macro names can not be used for this.
+383     In line 3, "\%f[\%i]" should be "\&f[\%i]".
+383     In the sort example, it should be stated that the array is 1-based.
+387     Change "You can list" to "You can get a list" (5th paragraph)
+393     \Fverify() description.  The 3rd sentence could be stated more clearly
+        as "If all characters in string2 are also in string1, 0 is returned."
+398     Copying \ffiles() results to an array before is not required as of
+        C-Kermit 7.0 (see [637]Section 7.3).
+403     In "(\%a + 3) * (\%b  5)", a minus sign is missing between b and 5.
+407     C-Kermit 7.0 no longer supports multiline GET.  Change
+        "get, \%1, \%2" to "get {\%1} {\%2}" or "get /as:{\%2} {\%1}".
+409     READ example while loop should be:
+        while success { echo \m(line), read line }
+409     "WRITE file" should be "WRITE keyword" (you can't put a filename there)
+        (The same applies to WRITE-LINE / WRITELN).
+414     \Funhexify() missing from Table 18-3.
+425     MINPUT definition, change 2nd "text2" to "text3".
+436     Several lines are missing from the UNIXLOGIN macro listing.
+        After the "xif fail" block, insert:
+
+          out \%1\13                    ; Send username, carriage return
+          inp 5 Password:               ; Wait 5 sec for this prompt
+          if fail end 1 No password prompt
+          pause                         ; Wait a sec
+          out \%2\13                    ; Send password
+
+440     Change "set terminal byteszie" to "set terminal bytesize".
+        Change "input Password:" to "input 10 Password".
+448     Franchise script: "access line" should be "access \m(line)".
+453     There are two incorrectly coded IF statements in the DELIVER macro
+        definition.  Replace both occurrences of "if > \%1 \%3 {" with
+        "xif > \%i \%3 {" (replace "if" by "xif" and "\%1" with "\%i").
+453     "the the" (last paragraph) should be "the".
+454     EOT (last paragraph) is End of Transmission, not End of Text.
+457     _DEFINE definition: "name constructed" should be "name is constructed".
+457     "macro for and" (last paragraph) should be "macro and".
+459     Should explain that \v(user) is a legal abbreviation of \v(userid).
+480     Figure II-2 is backwards; the least-significant bit is transmitted
+        first, then up to the highest, and the parity bit last.
+534     The VMS Appendix section on Odd Record Lengths no longer applies;
+        C-Kermit 7.0 handles odd record lengths as well as even ones.
+559     Table VIII-3, Portuguese entry.  Column 4/00 should show section sign,
+        not acute accent.
+560-563 HP-Roman8 missing from Table VII-4; there wasn't room to squeeze it in.
+        It is listed in section II(6).
+565     "d stroke" in Table VII-5 has the wrong appearance; the stem should
+        be upright.  The letter shown in the table is actually a lowercase
+        Icelandic eth, which has a curved stem.
+601-604 BeBox, BeOS, Plan 9, and probably others not listed in trademarks.
+604     The words "SCRIBE TEXT FORMATTER" appear at the end of the last
+        sentence of the first paragraph of the Colophon.  They should have
+        been in the Index.
+Index:  Missing entries: SET { SEND, RECEIVE } PATHNAMES, Call waiting, ...
+        \F()            Page 605, add also 413-414
+        \Fbreak         389
+        \Fcapitalize    390
+        \Fchecksum      414
+        \Fcrc16         414
+        \Fexecute       414
+        \Fhexify        390
+        \Fltrim         391
+        \Frepeat        392
+        \Fspawn         392
+        \Ftod2secs      399
+        \v() built_in   Page 606, add also 361-364
+        \v(_line)       354, 361
+        \v(apcactive)   361
+        \v(charset)     362
+        \v(cpu)         362
+        \v(crc16)       357, 362
+        \v(d$xxx)       add page 362
+        \v(dialnumber)  362
+        \v(dialresult)  362
+        \v(errno)       362
+        \v(errstring)   362
+        \v(exedir)      362
+        \v(inidir)      363
+        \v(ipaddress)   363
+        \v(keyboard)    363
+        \v(macro)       363
+        \v(minput)      363
+        \v(m_xxx)       94, 363
+        \v(password)    364
+        \v(query)       364
+        \v(prompt)      364
+        \v(speed)       356, 364
+        \v(startup)     364
+        \v(status)      364
+        \v(sysid)       364
+        \v(system)      364
+        \v(fsize)       at lower half page 606 should read \v(tfsize)
+        \v(xversion)    364
+        BEEP Command    40
+        SET FLOW        62, 212
+
+   Figure II-5 on page 493. The pin assignments of the Mini Din-8
+   connector are not described anywhere. As noted in the text, these tend
+   to vary from vendor to vendor. One common arrangement is:
+
+  1. HSKout (Handshake out -- definition depends on software)
+  2. HSKin  (Handshake in or external clock)
+  3. TxD-
+  4. Not used
+  5. RxD-
+  6. TxD+
+  7. Not used
+  8. RxD+
+
+   Note the "balanced pairs" for Receive Data (RxD) and Transmit Data
+   (TxD), and the utter lack of modem signals. These connectors follow
+   the RS-423 standard, rather than RS-232. In some arrangements, Pin 1
+   is used for DTR and Pin 2 for CD; in others Pin 1 is RTS and Pin 2 is
+   CTS.
+
+   Please send reports of other errors to the authors, as well as
+   suggestions for improvements, additional index entries, and any other
+   comments:
+
+   [638]kermit@columbia.edu
+     _________________________________________________________________
+
+APPENDIX V. ADDITIONAL COPYRIGHT NOTICES
+
+   The following copyrights cover some of the source code used in the
+   development of C-Kermit, Kermit 95, or Kermit 95 support libraries.
+
+/*****************************************************************************/
+/*                                                                           */
+/*              Copyright (c) 1995 by Oy Online Solutions Ltd.               */
+/*                                                                           */
+/*   Distribution of this source code is strictly forbbidden. Use of this    */
+/*   source code is granted to the University of Columbia C-Kermit project   */
+/*   to be distributed in binary format only. Please familiarize yourself    */
+/*   with the accompanying LICENSE.P file.                                   */
+/*                                                                           */
+/*****************************************************************************/
+
+   used for Xmodem, Ymodem, and Zmodem protocol in Kermit 95 (p95.dll,
+   p2.dll)
+     _________________________________________________________________
+
+   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.
+
+   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.
+
+   Used for Secure Remote Password (TM) protocol (SRP) in C-Kermit,
+   Kermit 95 (k95.exe, k2.exe, k95crypt.dll, k2crypt.dll)
+     _________________________________________________________________
+
+   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.
+
+   Used for Telnet Authentication Option, Telnet Encryption Option, and
+   Kerberos (TM) authentication in C-Kermit, Kermit 95 (k95.exe, k2.exe,
+   k95crypt.dll, k2crypt.dll)
+     _________________________________________________________________
+
+   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.
+
+   Used for Telnet Authentication Option, Telnet Encryption Option, and
+   Kerberos (TM) authentication in C-Kermit, Kermit 95 (k95.exe, k2.exe,
+   k95crypt.dll, k2crypt.dll)
+     _________________________________________________________________
+
+   Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) All rights
+   reserved.
+
+   This package is an DES implementation written by Eric Young
+   (eay@cryptsoft.com). The implementation was written so as to conform
+   with MIT's libdes.
+
+   This library is free for commercial and non-commercial use as long as
+   the following conditions are aheared to. The following conditions
+   apply to all code found in this distribution.
+
+   Copyright remains Eric Young's, and as such any Copyright notices in
+   the code are not to be removed. If this package is used in a product,
+   Eric Young should be given attribution as the author of that the SSL
+   library. This can be in the form of a textual message at program
+   startup or in documentation (online or textual) provided with the
+   package.
+
+   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 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 Eric Young (eay@cryptsoft.com)
+
+   THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+
+   The license and distribution terms for any publically available
+   version or derivative of this code cannot be changed. i.e. this code
+   cannot simply be copied and put under another distrubution license
+   [including the GNU Public License.]
+
+   The reason behind this being stated in this direct manner is past
+   experience in code simply being copied and the attribution removed
+   from it and then being distributed as part of other packages. This
+   implementation was a non-trivial and unpaid effort.
+
+   Used DES encryption in Kermit 95 (k95crypt.dll, k2crypt.dll)
+     _________________________________________________________________
+
+ * This is version 1.1 of CryptoLib
+ *
+ * The authors of this software are Jack Lacy, Don Mitchell and Matt Blaze
+ *              Copyright (c) 1991, 1992, 1993, 1994, 1995 by AT&T.
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * NOTE:
+ * Some of the algorithms in cryptolib may be covered by patents.
+ * It is the responsibility of the user to ensure that any required
+ * licenses are obtained.
+ *
+ *
+ * SOME PARTS OF CRYPTOLIB MAY BE RESTRICTED UNDER UNITED STATES EXPORT
+ * REGULATIONS.
+ *
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+
+   Used for Big Number library in Kermit 95 (k95crypt.dll, k2crypt.dll).
+
+   [ [639]Top ] [ [640]C-Kermit ] [ [641]Kermit Home ]
+     _________________________________________________________________
+
+   CKERMIT70.HTM / The Kermit Project / Columbia University / 8 Feb 2000
+
+References
+
+   1. http://www.columbia.edu/kermit/ckermit70.html#contents
+   2. http://www.columbia.edu/kermit/ckermit.html
+   3. http://www.columbia.edu/kermit/index.htm
+   4. mailto:kermit-support@columbia.edu
+   5. http://www.columbia.edu/kermit/
+   6. http://www.kermit-project.org/
+   7. http://www.columbia.nyc.ny.us/kermit/
+   8. ftp://kermit.columbia.edu/kermit/f/COPYING.TXT
+   9. ftp://kermit.columbia.edu/kermit/f/ckcmai.c
+  10. http://www.columbia.edu/kermit/ckermit70.html#xv
+  11. http://www.columbia.edu/kermit/ckb2.htm
+  12. ftp://kermit.columbia.edu/kermit/f/ckcbwr.txt
+  13. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+  14. ftp://kermit.columbia.edu/kermit/f/ckvbwr.txt
+  15. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+  16. ftp://kermit.columbia.edu/kermit/f/ckermit70.txt
+  17. ftp://kermit.columbia.edu/kermit/f/security.txt
+  18. http://www.columbia.edu/kermit/security.htm
+  19. ftp://kermit.columbia.edu/kermit/f/iksd.txt
+  20. http://www.columbia.edu/kermit/iksd.htm
+  21. http://www.columbia.edu/kermit/cuiksd.htm
+  22. ftp://kermit.columbia.edu/kermit/f/telnet.txt
+  23. http://www.columbia.edu/kermit/telnet.htm
+  24. ftp://kermit.columbia.edu/kermit/f/COPYING.TXT
+  25. http://www.columbia.edu/kermit/k95.html
+  26. http://www.opensource.org/
+  27. http://www.columbia.edu/kermit/ckb2.htm
+  28. http://www.columbia.edu/kermit/ckermit70.html#xi
+  29. http://www.columbia.edu/kermit/ckermit70.html#xii
+  30. http://www.columbia.edu/kermit/ckermit70.html#x0
+  31. http://www.columbia.edu/kermit/ckermit70.html#x1
+  32. http://www.columbia.edu/kermit/ckermit70.html#x1.0
+  33. http://www.columbia.edu/kermit/ckermit70.html#x1.1
+  34. http://www.columbia.edu/kermit/ckermit70.html#x1.2
+  35. http://www.columbia.edu/kermit/ckermit70.html#x1.3
+  36. http://www.columbia.edu/kermit/ckermit70.html#x1.4
+  37. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+  38. http://www.columbia.edu/kermit/ckermit70.html#x1.5.1
+  39. http://www.columbia.edu/kermit/ckermit70.html#x1.5.2
+  40. http://www.columbia.edu/kermit/ckermit70.html#x1.5.3
+  41. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+  42. http://www.columbia.edu/kermit/ckermit70.html#x1.5.5
+  43. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+  44. http://www.columbia.edu/kermit/ckermit70.html#x1.7
+  45. http://www.columbia.edu/kermit/ckermit70.html#x1.8
+  46. http://www.columbia.edu/kermit/ckermit70.html#x1.9
+  47. http://www.columbia.edu/kermit/ckermit70.html#x1.10
+  48. http://www.columbia.edu/kermit/ckermit70.html#x1.11
+  49. http://www.columbia.edu/kermit/ckermit70.html#x1.11.1
+  50. http://www.columbia.edu/kermit/ckermit70.html#x1.11.2
+  51. http://www.columbia.edu/kermit/ckermit70.html#x1.11.3
+  52. http://www.columbia.edu/kermit/ckermit70.html#x1.11.4
+  53. http://www.columbia.edu/kermit/ckermit70.html#x1.11.5
+  54. http://www.columbia.edu/kermit/ckermit70.html#x1.11.6
+  55. http://www.columbia.edu/kermit/ckermit70.html#x1.11.7
+  56. http://www.columbia.edu/kermit/ckermit70.html#x1.12
+  57. http://www.columbia.edu/kermit/ckermit70.html#x1.13
+  58. http://www.columbia.edu/kermit/ckermit70.html#x1.14
+  59. http://www.columbia.edu/kermit/ckermit70.html#x1.15
+  60. http://www.columbia.edu/kermit/ckermit70.html#x1.16
+  61. http://www.columbia.edu/kermit/ckermit70.html#x1.17
+  62. http://www.columbia.edu/kermit/ckermit70.html#x1.18
+  63. http://www.columbia.edu/kermit/ckermit70.html#x1.19
+  64. http://www.columbia.edu/kermit/ckermit70.html#x1.20
+  65. http://www.columbia.edu/kermit/ckermit70.html#x1.21
+  66. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+  67. http://www.columbia.edu/kermit/ckermit70.html#x1.22.1
+  68. http://www.columbia.edu/kermit/ckermit70.html#x1.22.2
+  69. http://www.columbia.edu/kermit/ckermit70.html#x1.22.3
+  70. http://www.columbia.edu/kermit/ckermit70.html#x1.22.4
+  71. http://www.columbia.edu/kermit/ckermit70.html#x1.22.5
+  72. http://www.columbia.edu/kermit/ckermit70.html#x1.22.6
+  73. http://www.columbia.edu/kermit/ckermit70.html#x1.22.7
+  74. http://www.columbia.edu/kermit/ckermit70.html#x1.22.8
+  75. http://www.columbia.edu/kermit/ckermit70.html#x1.23
+  76. http://www.columbia.edu/kermit/ckermit70.html#x1.24
+  77. http://www.columbia.edu/kermit/ckermit70.html#x2
+  78. http://www.columbia.edu/kermit/ckermit70.html#x2.0
+  79. http://www.columbia.edu/kermit/ckermit70.html#x2.1
+  80. http://www.columbia.edu/kermit/ckermit70.html#x2.1.1
+  81. http://www.columbia.edu/kermit/ckermit70.html#x2.1.2
+  82. http://www.columbia.edu/kermit/ckermit70.html#x2.1.3
+  83. http://www.columbia.edu/kermit/ckermit70.html#x2.1.4
+  84. http://www.columbia.edu/kermit/ckermit70.html#x2.1.5
+  85. http://www.columbia.edu/kermit/ckermit70.html#x2.1.6
+  86. http://www.columbia.edu/kermit/ckermit70.html#x2.1.7
+  87. http://www.columbia.edu/kermit/ckermit70.html#x2.1.8
+  88. http://www.columbia.edu/kermit/ckermit70.html#x2.1.9
+  89. http://www.columbia.edu/kermit/ckermit70.html#x2.1.10
+  90. http://www.columbia.edu/kermit/ckermit70.html#x2.1.11
+  91. http://www.columbia.edu/kermit/ckermit70.html#x2.1.12
+  92. http://www.columbia.edu/kermit/ckermit70.html#x2.1.13
+  93. http://www.columbia.edu/kermit/ckermit70.html#x2.1.14
+  94. http://www.columbia.edu/kermit/ckermit70.html#x2.1.15
+  95. http://www.columbia.edu/kermit/ckermit70.html#x2.1.16
+  96. http://www.columbia.edu/kermit/ckermit70.html#x2.2
+  97. http://www.columbia.edu/kermit/ckermit70.html#x2.2.1
+  98. http://www.columbia.edu/kermit/ckermit70.html#x2.2.2
+  99. http://www.columbia.edu/kermit/ckermit70.html#x2.3
+ 100. http://www.columbia.edu/kermit/ckermit70.html#x2.3.0
+ 101. http://www.columbia.edu/kermit/ckermit70.html#x2.3.1
+ 102. http://www.columbia.edu/kermit/ckermit70.html#x2.3.2
+ 103. http://www.columbia.edu/kermit/ckermit70.html#x2.3.3
+ 104. http://www.columbia.edu/kermit/ckermit70.html#x2.3.4
+ 105. http://www.columbia.edu/kermit/ckermit70.html#x2.3.5
+ 106. http://www.columbia.edu/kermit/ckermit70.html#x2.3.6
+ 107. http://www.columbia.edu/kermit/ckermit70.html#x2.4
+ 108. http://www.columbia.edu/kermit/ckermit70.html#x2.5
+ 109. http://www.columbia.edu/kermit/ckermit70.html#x2.6
+ 110. http://www.columbia.edu/kermit/ckermit70.html#x2.7
+ 111. http://www.columbia.edu/kermit/ckermit70.html#x2.7.0
+ 112. http://www.columbia.edu/kermit/ckermit70.html#x2.7.1
+ 113. http://www.columbia.edu/kermit/ckermit70.html#x2.7.2
+ 114. http://www.columbia.edu/kermit/ckermit70.html#x2.7.3
+ 115. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4
+ 116. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.1
+ 117. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.2
+ 118. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.3
+ 119. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.4
+ 120. http://www.columbia.edu/kermit/ckermit70.html#x2.7.4.5
+ 121. http://www.columbia.edu/kermit/ckermit70.html#x2.8
+ 122. http://www.columbia.edu/kermit/ckermit70.html#x2.9
+ 123. http://www.columbia.edu/kermit/ckermit70.html#x2.9.1
+ 124. http://www.columbia.edu/kermit/ckermit70.html#x2.9.2
+ 125. http://www.columbia.edu/kermit/ckermit70.html#x2.10
+ 126. http://www.columbia.edu/kermit/ckermit70.html#x2.11
+ 127. http://www.columbia.edu/kermit/ckermit70.html#x2.12
+ 128. http://www.columbia.edu/kermit/ckermit70.html#x2.13
+ 129. http://www.columbia.edu/kermit/ckermit70.html#x2.14
+ 130. http://www.columbia.edu/kermit/ckermit70.html#x2.15
+ 131. http://www.columbia.edu/kermit/ckermit70.html#x3
+ 132. http://www.columbia.edu/kermit/ckermit70.html#x3.1
+ 133. http://www.columbia.edu/kermit/ckermit70.html#x3.2
+ 134. http://www.columbia.edu/kermit/ckermit70.html#x3.3
+ 135. http://www.columbia.edu/kermit/ckermit70.html#x3.4
+ 136. http://www.columbia.edu/kermit/ckermit70.html#x4
+ 137. http://www.columbia.edu/kermit/ckermit70.html#x4.0
+ 138. http://www.columbia.edu/kermit/ckermit70.html#x4.1
+ 139. http://www.columbia.edu/kermit/ckermit70.html#x4.1.1
+ 140. http://www.columbia.edu/kermit/ckermit70.html#x4.1.2
+ 141. http://www.columbia.edu/kermit/ckermit70.html#x4.1.3
+ 142. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 143. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1
+ 144. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1.1
+ 145. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1.2
+ 146. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1.3
+ 147. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 148. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2.1
+ 149. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2.2
+ 150. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3
+ 151. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3.1
+ 152. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3.2
+ 153. http://www.columbia.edu/kermit/ckermit70.html#x4.2.4
+ 154. http://www.columbia.edu/kermit/ckermit70.html#x4.2.5
+ 155. http://www.columbia.edu/kermit/ckermit70.html#x4.2.6
+ 156. http://www.columbia.edu/kermit/ckermit70.html#x4.2.7
+ 157. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8
+ 158. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.1
+ 159. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.2
+ 160. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.3
+ 161. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.4
+ 162. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 163. http://www.columbia.edu/kermit/ckermit70.html#x4.3.1
+ 164. http://www.columbia.edu/kermit/ckermit70.html#x4.3.2
+ 165. http://www.columbia.edu/kermit/ckermit70.html#x4.3.3
+ 166. http://www.columbia.edu/kermit/ckermit70.html#x4.3.4
+ 167. http://www.columbia.edu/kermit/ckermit70.html#x4.4
+ 168. http://www.columbia.edu/kermit/ckermit70.html#x4.4.1
+ 169. http://www.columbia.edu/kermit/ckermit70.html#x4.4.1.1
+ 170. http://www.columbia.edu/kermit/ckermit70.html#x4.4.1.2
+ 171. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2
+ 172. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2.1
+ 173. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2.1.1
+ 174. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2.1.2
+ 175. http://www.columbia.edu/kermit/ckermit70.html#x4.4.2.2
+ 176. http://www.columbia.edu/kermit/ckermit70.html#x4.5
+ 177. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 178. http://www.columbia.edu/kermit/ckermit70.html#x4.5.2
+ 179. http://www.columbia.edu/kermit/ckermit70.html#x4.5.2.1
+ 180. http://www.columbia.edu/kermit/ckermit70.html#x4.5.2.2
+ 181. http://www.columbia.edu/kermit/ckermit70.html#x4.5.3
+ 182. http://www.columbia.edu/kermit/ckermit70.html#x4.5.4
+ 183. http://www.columbia.edu/kermit/ckermit70.html#x4.6
+ 184. http://www.columbia.edu/kermit/ckermit70.html#x4.7
+ 185. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 186. http://www.columbia.edu/kermit/ckermit70.html#x4.7.2
+ 187. http://www.columbia.edu/kermit/ckermit70.html#x4.7.3
+ 188. http://www.columbia.edu/kermit/ckermit70.html#x4.8
+ 189. http://www.columbia.edu/kermit/ckermit70.html#x4.8.1
+ 190. http://www.columbia.edu/kermit/ckermit70.html#x4.8.2
+ 191. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 192. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 193. http://www.columbia.edu/kermit/ckermit70.html#x4.9.2
+ 194. http://www.columbia.edu/kermit/ckermit70.html#x4.9.3
+ 195. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 196. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 197. http://www.columbia.edu/kermit/ckermit70.html#x4.11.1
+ 198. http://www.columbia.edu/kermit/ckermit70.html#x4.11.2
+ 199. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 200. http://www.columbia.edu/kermit/ckermit70.html#x4.11.4
+ 201. http://www.columbia.edu/kermit/ckermit70.html#x4.11.5
+ 202. http://www.columbia.edu/kermit/ckermit70.html#x4.11.6
+ 203. http://www.columbia.edu/kermit/ckermit70.html#x4.12
+ 204. http://www.columbia.edu/kermit/ckermit70.html#x4.13
+ 205. http://www.columbia.edu/kermit/ckermit70.html#x4.14
+ 206. http://www.columbia.edu/kermit/ckermit70.html#x4.15
+ 207. http://www.columbia.edu/kermit/ckermit70.html#x4.16
+ 208. http://www.columbia.edu/kermit/ckermit70.html#x4.17
+ 209. http://www.columbia.edu/kermit/ckermit70.html#x4.17.1
+ 210. http://www.columbia.edu/kermit/ckermit70.html#x4.17.2
+ 211. http://www.columbia.edu/kermit/ckermit70.html#x4.18
+ 212. http://www.columbia.edu/kermit/ckermit70.html#x4.19
+ 213. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 214. http://www.columbia.edu/kermit/ckermit70.html#x4.20.1
+ 215. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2
+ 216. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.1
+ 217. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.2
+ 218. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.3
+ 219. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.4
+ 220. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.5
+ 221. http://www.columbia.edu/kermit/ckermit70.html#x4.20.3
+ 222. http://www.columbia.edu/kermit/ckermit70.html#x4.21
+ 223. http://www.columbia.edu/kermit/ckermit70.html#x4.22
+ 224. http://www.columbia.edu/kermit/ckermit70.html#x4.22.1
+ 225. http://www.columbia.edu/kermit/ckermit70.html#x4.22.2
+ 226. http://www.columbia.edu/kermit/ckermit70.html#x4.22.3
+ 227. http://www.columbia.edu/kermit/ckermit70.html#x4.22.4
+ 228. http://www.columbia.edu/kermit/ckermit70.html#x4.22.5
+ 229. http://www.columbia.edu/kermit/ckermit70.html#x4.22.6
+ 230. http://www.columbia.edu/kermit/ckermit70.html#x4.22.7
+ 231. http://www.columbia.edu/kermit/ckermit70.html#x4.22.8
+ 232. http://www.columbia.edu/kermit/ckermit70.html#x4.23
+ 233. http://www.columbia.edu/kermit/ckermit70.html#x4.24
+ 234. http://www.columbia.edu/kermit/ckermit70.html#x4.25
+ 235. http://www.columbia.edu/kermit/ckermit70.html#x5
+ 236. http://www.columbia.edu/kermit/ckermit70.html#x5.0
+ 237. http://www.columbia.edu/kermit/ckermit70.html#x5.1
+ 238. http://www.columbia.edu/kermit/ckermit70.html#x5.2
+ 239. http://www.columbia.edu/kermit/ckermit70.html#x5.3
+ 240. http://www.columbia.edu/kermit/ckermit70.html#x5.3.1
+ 241. http://www.columbia.edu/kermit/ckermit70.html#x5.3.2
+ 242. http://www.columbia.edu/kermit/ckermit70.html#x5.4
+ 243. http://www.columbia.edu/kermit/ckermit70.html#x5.5
+ 244. http://www.columbia.edu/kermit/ckermit70.html#x5.6
+ 245. http://www.columbia.edu/kermit/ckermit70.html#x5.7
+ 246. http://www.columbia.edu/kermit/ckermit70.html#x6
+ 247. http://www.columbia.edu/kermit/ckermit70.html#x6.0
+ 248. http://www.columbia.edu/kermit/ckermit70.html#x6.1
+ 249. http://www.columbia.edu/kermit/ckermit70.html#x6.2
+ 250. http://www.columbia.edu/kermit/ckermit70.html#x6.3
+ 251. http://www.columbia.edu/kermit/ckermit70.html#x6.4
+ 252. http://www.columbia.edu/kermit/ckermit70.html#x6.5
+ 253. http://www.columbia.edu/kermit/ckermit70.html#x6.6
+ 254. http://www.columbia.edu/kermit/ckermit70.html#x6.6.1
+ 255. http://www.columbia.edu/kermit/ckermit70.html#x6.6.2
+ 256. http://www.columbia.edu/kermit/ckermit70.html#x6.6.2
+ 257. http://www.columbia.edu/kermit/ckermit70.html#x6.6.3
+ 258. http://www.columbia.edu/kermit/ckermit70.html#x6.6.4
+ 259. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5
+ 260. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.1
+ 261. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.2
+ 262. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.3
+ 263. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.4
+ 264. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.5
+ 265. http://www.columbia.edu/kermit/ckermit70.html#x6.7
+ 266. http://www.columbia.edu/kermit/ckermit70.html#x7
+ 267. http://www.columbia.edu/kermit/ckermit70.html#x7.0
+ 268. http://www.columbia.edu/kermit/ckermit70.html#x7.1
+ 269. http://www.columbia.edu/kermit/ckermit70.html#x7.1.1
+ 270. http://www.columbia.edu/kermit/ckermit70.html#x7.1.2
+ 271. http://www.columbia.edu/kermit/ckermit70.html#x7.1.3
+ 272. http://www.columbia.edu/kermit/ckermit70.html#x7.1.4
+ 273. http://www.columbia.edu/kermit/ckermit70.html#x7.2
+ 274. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 275. http://www.columbia.edu/kermit/ckermit70.html#x7.4
+ 276. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 277. http://www.columbia.edu/kermit/ckermit70.html#x7.6
+ 278. http://www.columbia.edu/kermit/ckermit70.html#x7.7
+ 279. http://www.columbia.edu/kermit/ckermit70.html#x7.8
+ 280. http://www.columbia.edu/kermit/ckermit70.html#x7.9
+ 281. http://www.columbia.edu/kermit/ckermit70.html#x7.9.1
+ 282. http://www.columbia.edu/kermit/ckermit70.html#x7.9.2
+ 283. http://www.columbia.edu/kermit/ckermit70.html#x7.10
+ 284. http://www.columbia.edu/kermit/ckermit70.html#x7.10.1
+ 285. http://www.columbia.edu/kermit/ckermit70.html#x7.10.2
+ 286. http://www.columbia.edu/kermit/ckermit70.html#x7.10.3
+ 287. http://www.columbia.edu/kermit/ckermit70.html#x7.10.4
+ 288. http://www.columbia.edu/kermit/ckermit70.html#x7.10.5
+ 289. http://www.columbia.edu/kermit/ckermit70.html#x7.10.6
+ 290. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 291. http://www.columbia.edu/kermit/ckermit70.html#x7.10.8
+ 292. http://www.columbia.edu/kermit/ckermit70.html#x7.10.9
+ 293. http://www.columbia.edu/kermit/ckermit70.html#x7.10.10
+ 294. http://www.columbia.edu/kermit/ckermit70.html#x7.11
+ 295. http://www.columbia.edu/kermit/ckermit70.html#x7.12
+ 296. http://www.columbia.edu/kermit/ckermit70.html#x7.13
+ 297. http://www.columbia.edu/kermit/ckermit70.html#x7.14
+ 298. http://www.columbia.edu/kermit/ckermit70.html#x7.15
+ 299. http://www.columbia.edu/kermit/ckermit70.html#x7.16
+ 300. http://www.columbia.edu/kermit/ckermit70.html#x7.17
+ 301. http://www.columbia.edu/kermit/ckermit70.html#x7.18
+ 302. http://www.columbia.edu/kermit/ckermit70.html#x7.19
+ 303. http://www.columbia.edu/kermit/ckermit70.html#x7.20
+ 304. http://www.columbia.edu/kermit/ckermit70.html#x7.20.1
+ 305. http://www.columbia.edu/kermit/ckermit70.html#x7.20.2
+ 306. http://www.columbia.edu/kermit/ckermit70.html#x7.21
+ 307. http://www.columbia.edu/kermit/ckermit70.html#x7.22
+ 308. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 309. http://www.columbia.edu/kermit/ckermit70.html#x7.24
+ 310. http://www.columbia.edu/kermit/ckermit70.html#x7.25
+ 311. http://www.columbia.edu/kermit/ckermit70.html#x7.26
+ 312. http://www.columbia.edu/kermit/ckermit70.html#x7.26.1
+ 313. http://www.columbia.edu/kermit/ckermit70.html#x7.26.2
+ 314. http://www.columbia.edu/kermit/ckermit70.html#x7.27
+ 315. http://www.columbia.edu/kermit/ckermit70.html#x8
+ 316. http://www.columbia.edu/kermit/ckermit70.html#x9
+ 317. http://www.columbia.edu/kermit/ckermit70.html#x9.0
+ 318. http://www.columbia.edu/kermit/ckermit70.html#x9.1
+ 319. http://www.columbia.edu/kermit/ckermit70.html#x9.2
+ 320. http://www.columbia.edu/kermit/ckermit70.html#x9.3
+ 321. http://www.columbia.edu/kermit/ckermit70.html#x10
+ 322. http://www.columbia.edu/kermit/ckermit70.html#xiii
+ 323. http://www.columbia.edu/kermit/ckermit70.html#xiii.1
+ 324. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.1
+ 325. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.2
+ 326. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.2.1
+ 327. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.2.2
+ 328. http://www.columbia.edu/kermit/ckermit70.html#xiii.1.2.3
+ 329. http://www.columbia.edu/kermit/ckermit70.html#xiii.2
+ 330. http://www.columbia.edu/kermit/ckermit70.html#xiv
+ 331. http://www.columbia.edu/kermit/ckermit70.html#xv
+ 332. http://www.columbia.edu/kermit/ckb2.htm
+ 333. http://www.columbia.edu/kermit/ckbreviews.html
+ 334. http://www.bhusa.com/
+ 335. http://www.columbia.edu/kermit/manuals.html#ckde
+ 336. http://www.columbia.edu/kermit/manuals.html#ktb
+ 337. http://www.columbia.edu/kermit/news.html
+ 338. news:comp.protocols.kermit.announce
+ 339. news:comp.protocols.kermit.misc
+ 340. http://www.columbia.edu/kermit/ckb2.htm
+ 341. http://www.columbia.edu/kermit/ckermit70.html#x4
+ 342. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 343. http://www.columbia.edu/kermit/ckermit70.html#x4.23
+ 344. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 345. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 346. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 347. http://www.columbia.edu/kermit/ckermit70.html#x4.9.
+ 348. http://www.columbia.edu/kermit/ckb2.htm
+ 349. http://www.columbia.edu/kermit/ckermit70.html#x7.9.2
+ 350. http://www.columbia.edu/kermit/ckermit70.html#x2.15
+ 351. http://www.columbia.edu/kermit/ckermit70.html#x9.1
+ 352. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 353. http://www.columbia.edu/kermit/ckermit70.html#x7.4
+ 354. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 355. http://www.columbia.edu/kermit/ckermit70.html#mjd
+ 356. http://www.columbia.edu/kermit/ckermit70.html#mjd
+ 357. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 358. http://www.columbia.edu/kermit/ckb2.htm
+ 359. http://www.columbia.edu/kermit/ckb2.htm
+ 360. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 361. http://www.columbia.edu/kermit/ckermit70.html#x2.12
+ 362. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 363. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 364. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5
+ 365. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 366. http://www.columbia.edu/kermit/ckermit70.html#x7.18
+ 367. http://www.columbia.edu/kermit/ckermit70.html#x7.4
+ 368. http://www.columbia.edu/kermit/ckermit70.html#x1.15
+ 369. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 370. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 371. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 372. http://www.columbia.edu/kermit/ckermit70.html#x7.1
+ 373. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 374. ftp://kermit.columbia.edu/kermit/f/ckccfg.txt
+ 375. ftp://kermit.columbia.edu/kermit/f/ckccfg.txt
+ 376. http://www.columbia.edu/kermit/ckermit70.html#x1.22.4
+ 377. http://www.columbia.edu/kermit/ckermit70.html#x1.22.5
+ 378. http://www.columbia.edu/kermit/ckb2.htm
+ 379. http://www.columbia.edu/kermit/ckermit70.html#x1.22.5
+ 380. http://www.columbia.edu/kermit/ckermit70.html#x7.12
+ 381. http://www.columbia.edu/kermit/ckermit70.html#x2.1.16
+ 382. http://www.columbia.edu/kermit/ckermit70.html#x2.7
+ 383. http://www.columbia.edu/kermit/ckermit70.html#x2.3.5
+ 384. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 385. http://www.telefonica.es/cambiodenumeracion/
+ 386. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 387. http://www.columbia.edu/kermit/ckb2.htm
+ 388. http://www.columbia.edu/kermit/ckermit70.html#x2.2.2
+ 389. http://www.columbia.edu/kermit/ckermit70.html#x2.1.11
+ 390. http://www.columbia.edu/kermit/ckermit70.html#x2.1.13
+ 391. http://www.columbia.edu/kermit/ckermit70.html#x2.1.12
+ 392. http://www.columbia.edu/kermit/ckb2.htm
+ 393. http://www.columbia.edu/kermit/ckermit70.html#x2.1.1
+ 394. http://www.columbia.edu/kermit/ckb2.htm
+ 395. http://www.columbia.edu/kermit/ckb2.htm
+ 396. http://www.columbia.edu/kermit/ckermit70.html#x2.1.7
+ 397. http://www.columbia.edu/kermit/ckermit70.html#x2.1.6
+ 398. http://www.columbia.edu/kermit/ckb2.htm
+ 399. ftp://kermit.columbia.edu/kermit/f/telnet.txt
+ 400. http://www.columbia.edu/kermit/telnet.htm
+ 401. ftp://kermit.columbia.edu/kermit/f/telnet.txt
+ 402. http://www.columbia.edu/kermit/telnet.htm
+ 403. ftp://ftp.isi.edu/in-notes/rfc1572.txt
+ 404. ftp://ftp.isi.edu/in-notes/rfc779.txt
+ 405. http://www.columbia.edu/kermit/ckb2.htm
+ 406. http://www.columbia.edu/kermit/ckermit70.html#x2.10
+ 407. http://www.columbia.edu/kermit/ckermit70.html#x2.8
+ 408. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 409. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 410. http://www.psy.uq.oz.au/~ftp/Crypto/
+ 411. http://www.columbia.edu/kermit/security.htm
+ 412. http://srp.stanford.edu/srp/
+ 413. http://www.columbia.edu/kermit/ckermit70.html#x2.7.1,
+ 414. ftp://kermit.columbia.edu/kermit/f/ckccfg.txt
+ 415. http://www.columbia.edu/kermit/security.htm
+ 416. http://www.columbia.edu/kermit/ckb2.htm
+ 417. http://www.columbia.edu/kermit/ckermit70.html#x2.7
+ 418. http://www.columbia.edu/kermit/ckermit70.html#x2.0
+ 419. ftp://kermit.columbia.edu/kermit/f/ckuins.txt
+ 420. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+ 421. ftp://kermit.columbia.edu/kermit/f/ckuins.txt
+ 422. http://www.columbia.edu/kermit/iksd.html#x4.2
+ 423. http://www.columbia.edu/kermit/iksd.html
+ 424. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.1
+ 425. ftp://ftp.isi.edu/in-notes/rfc1945.txt
+ 426. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 427. http://www.columbia.edu/kermit/ckermit70.html#x3.2
+ 428. http://www.columbia.edu/kermit/ckermit70.html#x3.2
+ 429. http://www.columbia.edu/kermit/ckb2.htm
+ 430. http://www.columbia.edu/kermit/ckb2.htm
+ 431. http://www.columbia.edu/kermit/ckermit70.html#x5.4
+ 432. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+ 433. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 434. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 435. http://www.columbia.edu/kermit/ckermit70.html#x4.7.3
+ 436. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 437. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 438. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 439. http://www.columbia.edu/kermit/ckermit70.html#x4.15
+ 440. http://www.columbia.edu/kermit/ckermit70.html#x4.2.4
+ 441. http://www.columbia.edu/kermit/ckermit70.html#x4.7
+ 442. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3
+ 443. http://www.columbia.edu/kermit/ckermit70.html#x4.2.1.3
+ 444. http://www.columbia.edu/kermit/ckb2.htm
+ 445. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 446. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 447. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.2
+ 448. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 449. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 450. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 451. http://www.columbia.edu/kermit/ckermit70.html#x4.15
+ 452. http://www.telstra.com.au/docs/PGP/
+ 453. http://www.telstra.com.au/docs/PGP/pgpdoc2/pgpdoc2_17.html
+ 454. http://www.columbia.edu/kermit/security.htm
+ 455. http://www.columbia.edu/kermit/ckermit70.html#x2.7
+ 456. http://www.columbia.edu/kermit/ckb2.htm
+ 457. http://www.columbia.edu/kermit/ckermit70.html#x2.14
+ 458. http://www.columbia.edu/kermit/ckermit70.html#x1.23
+ 459. http://www.columbia.edu/kermit/ckermit70.html#x4.7
+ 460. http://www.columbia.edu/kermit/ckb2.htm
+ 461. http://www.columbia.edu/kermit/ckb2.htm
+ 462. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 463. http://www.columbia.edu/kermit/ckb2.htm
+ 464. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+ 465. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 466. http://www.columbia.edu/kermit/ckermit70.html#x1.5.5
+ 467. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 468. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 469. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+ 470. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 471. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+ 472. http://www.columbia.edu/kermit/ckermit70.html#x1.5.5
+ 473. http://www.columbia.edu/kermit/ckb2.htm
+ 474. http://www.columbia.edu/kermit/ckb2.htm
+ 475. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 476. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 477. http://www.columbia.edu/kermit/ckermit70.html#x7.10
+ 478. http://www.columbia.edu/kermit/ckermit70.html#x7.10.11
+ 479. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 480. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 481. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 482. http://www.columbia.edu/kermit/ckermit70.html#x1.5.4
+ 483. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 484. http://www.columbia.edu/kermit/ckermit70.html#x4.0.6
+ 485. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 486. http://www.columbia.edu/kermit/ckermit70.html#x4.1
+ 487. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 488. http://www.columbia.edu/kermit/ckb2.htm
+ 489. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 490. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 491. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 492. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 493. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 494. http://www.columbia.edu/kermit/ckermit70.html#x4.2.2
+ 495. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 496. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 497. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 498. http://www.columbia.edu/kermit/ckermit70.html#x1.11.5
+ 499. http://www.columbia.edu/kermit/ckermit70.html#x4.0.6
+ 500. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 501. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 502. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 503. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 504. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 505. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 506. http://www.columbia.edu/kermit/ckermit70.html#x7.10
+ 507. http://www.columbia.edu/kermit/ckermit70.html#x7.10.5
+ 508. http://www.columbia.edu/kermit/ckermit70.html#x7.10.3
+ 509. http://www.columbia.edu/kermit/ckermit70.html#x7.10.5
+ 510. http://www.columbia.edu/kermit/ckb2.htm
+ 511. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 512. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 513. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 514. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 515. http://www.columbia.edu/kermit/ckermit70.html#x4.15
+ 516. http://www.columbia.edu/kermit/ckermit70.html#x4.18
+ 517. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 518. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 519. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 520. http://www.columbia.edu/kermit/ckermit70.html#x4.19
+ 521. http://www.columbia.edu/kermit/ckermit70.html#x4.16
+ 522. http://www.columbia.edu/kermit/ckermit70.html#x4.19
+ 523. http://www.columbia.edu/kermit/ckermit70.html#x4.20.2.3
+ 524. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 525. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.4
+ 526. http://www.columbia.edu/kermit/ckermit70.html#x4.22.2
+ 527. http://www.columbia.edu/kermit/ckermit70.html#x4.22.3
+ 528. http://www.columbia.edu/kermit/ckb2.htm
+ 529. http://www.columbia.edu/kermit/ckb2.htm
+ 530. http://www.columbia.edu/kermit/ckermit70.html#x9.3
+ 531. http://www.columbia.edu/kermit/ckermit70.html#x5.2.1
+ 532. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 533. http://www.columbia.edu/kermit/ckermit70.html#x4.5.2
+ 534. http://www.columbia.edu/kermit/ckermit70.html#x6.6
+ 535. http://www.columbia.edu/kermit/ckermit70.html#xiii
+ 536. http://www.columbia.edu/kermit/ckermit70.html#xiii
+ 537. ftp://ftp.isi.edu/in-notes/rfc1489.txt
+ 538. ftp://ftp.isi.edu/in-notes/rfc2319.txt
+ 539. http://www.unicode.org/
+ 540. http://www.columbia.edu/kermit/ckermit70.html#x6.6.2
+ 541. http://www.columbia.edu/kermit/ckermit70.html#x6.6.5.1
+ 542. ftp://ftp.isi.edu/in-notes/rfc2640.txt
+ 543. http://www.columbia.edu/kermit/ckermit70.html#x6.6.2
+ 544. http://www.columbia.edu/kermit/ckermit70.html#x6.0
+ 545. http://www.columbia.edu/kermit/ckermit70.html#x6.5
+ 546. http://www.columbia.edu/kermit/ckermit70.html#x6.4
+ 547. http://www.columbia.edu/kermit/ckb2.htm
+ 548. http://www.columbia.edu/kermit/ckermit70.html#x4.21
+ 549. http://www.columbia.edu/kermit/ckermit70.html#x6.5
+ 550. http://www.columbia.edu/kermit/ckermit70.html#x2.8
+ 551. http://www.columbia.edu/kermit/ckermit70.html#x7.7
+ 552. http://www.columbia.edu/kermit/ckermit70.html#x7.2
+ 553. http://www.columbia.edu/kermit/ckermit70.html#x1.19
+ 554. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 555. http://www.columbia.edu/kermit/ckermit70.html#x4.1
+ 556. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 557. http://www.columbia.edu/kermit/ckermit70.html#x4.1
+ 558. http://www.columbia.edu/kermit/ckermit70.html#x4.2
+ 559. http://www.columbia.edu/kermit/ckermit70.html#x2.1.11
+ 560. http://www.columbia.edu/kermit/ckermit70.html#x2.10
+ 561. http://www.columbia.edu/kermit/ckermit70.html#ferrstring
+ 562. http://www.columbia.edu/kermit/ckermit70.html#x4.2.5
+ 563. http://www.columbia.edu/kermit/ckermit70.html#x2.1.10
+ 564. http://www.columbia.edu/kermit/ckermit70.html#x9.1
+ 565. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 566. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 567. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+ 568. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 569. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 570. http://www.columbia.edu/kermit/ckermit70.html#x7.24
+ 571. http://www.columbia.edu/kermit/ckermit70.html#x7.24
+ 572. http://www.columbia.edu/kermit/ckermit70.html#x4.2.3
+ 573. http://www.columbia.edu/kermit/ckermit70.html#x7.12
+ 574. http://www.columbia.edu/kermit/ckermit70.html#x7.9
+ 575. http://www.columbia.edu/kermit/ckb2.htm
+ 576. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 577. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 578. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 579. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 580. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 581. http://www.columbia.edu/kermit/ckermit70.html#x4.2.8.4
+ 582. http://www.columbia.edu/kermit/ckermit70.html#x4.2.5
+ 583. http://www.columbia.edu/kermit/ckermit70.html#x7.8
+ 584. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 585. http://www.columbia.edu/kermit/ckb2.htm
+ 586. http://www.columbia.edu/kermit/ckermit70.html#x7.19
+ 587. http://www.columbia.edu/kermit/ckermit70.html#x7.16
+ 588. http://www.columbia.edu/kermit/ckermit70.html#x7.9.1
+ 589. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 590. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 591. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 592. http://www.columbia.edu/kermit/ckermit70.html#x4.5.1
+ 593. http://www.columbia.edu/kermit/ckermit70.html#x7.10
+ 594. http://www.columbia.edu/kermit/ckermit70.html#x7.10.10
+ 595. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 596. http://www.columbia.edu/kermit/ckermit70.html#x7.23
+ 597. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 598. http://www.columbia.edu/kermit/ckermit70.html#x7.10.7
+ 599. http://www.columbia.edu/kermit/ckermit70.html#x4.11.3
+ 600. http://www.columbia.edu/kermit/ckermit70.html#x7.10.11
+ 601. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 602. http://www.columbia.edu/kermit/ckermit70.html#x7.10.3
+ 603. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 604. http://www.columbia.edu/kermit/ckermit70.html#x7.9.2
+ 605. http://www.columbia.edu/kermit/ckb2.htm
+ 606. http://www.columbia.edu/kermit/ckermit70.html#x4.17.2
+ 607. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+ 608. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 609. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+ 610. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 611. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 612. http://www.columbia.edu/kermit/ckermit70.html#x1.22
+ 613. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 614. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 615. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 616. http://www.columbia.edu/kermit/ckermit70.html#x7.19
+ 617. http://www.columbia.edu/kermit/ckermit70.html#x4.9.1
+ 618. http://www.columbia.edu/kermit/ckermit70.html#x9.3
+ 619. http://www.columbia.edu/kermit/ckermit70.html#x7.5
+ 620. http://www.columbia.edu/kermit/ckb2.htm
+ 621. http://www.columbia.edu/kermit/ckermit70.html#x7.4
+ 622. http://www.columbia.edu/kermit/ckermit70.html#x7.20.2
+ 623. http://www.columbia.edu/kermit/ckermit70.html#x7.10.5
+ 624. http://www.columbia.edu/kermit/ckermit70.html#x7.10.9
+ 625. http://www.columbia.edu/kermit/ckermit70.html#x1.10
+ 626. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 627. http://www.columbia.edu/kermit/ckermit70.html#x4.7.1
+ 628. http://www.columbia.edu/kermit/iksd.html
+ 629. http://www.columbia.edu/kermit/ckermit70.html#x7.19
+ 630. http://www.columbia.edu/kermit/ckermit70.html#x4.10
+ 631. http://www.columbia.edu/kermit/ckermit70.html#x4.11
+ 632. http://www.columbia.edu/kermit/ckermit70.html#x4.3
+ 633. http://www.columbia.edu/kermit/gkermit.html
+ 634. http://www.columbia.edu/kermit/ckermit70.html#x4.20
+ 635. http://www.columbia.edu/kermit/gkermit.html
+ 636. http://www.columbia.edu/kermit/ckb2.htm
+ 637. http://www.columbia.edu/kermit/ckermit70.html#x7.3
+ 638. mailto:kermit@columbia.edu
+ 639. http://www.columbia.edu/kermit/ckermit70.html#top
+ 640. http://www.columbia.edu/kermit/ckermit.html
+ 641. http://www.columbia.edu/kermit/index.html
diff --git a/ckermit-8.0.211/ckermit80.txt b/ckermit-8.0.211/ckermit80.txt
new file mode 100644
index 0000000..493338a
--- /dev/null
+++ b/ckermit-8.0.211/ckermit80.txt
@@ -0,0 +1,10349 @@
+
+                           C-Kermit 8.0 Update Notes
+
+   [ [1]Contents ] [ [2]C-Kermit ] [ [3]Kermit Home ]
+
+              Second Supplement to Using C-Kermit, Second Edition
+
+For C-Kermit 8.0
+
+   As of C-Kermit version: 8.0.211
+   Date of C-Kermit release: 10 April 2003
+   This file last updated: Sat Apr 10 16:36:11 2004
+
+     * IF YOU ARE READING A PLAIN-TEXT version of this document, note
+       that it is a plain-text dump of a Web page. You can visit the
+       original (and possibly more up-to-date) Web page here:
+  [4]http://www.columbia.edu/kermit/ckermit80.html
+     * If you are reading the HTML version of this file with a GUI Web
+       browser, the features added since C-Kermit 8.0.201 are shown in
+       red if your browser and monitor permit. Features that were new to
+       versions 8.0.200 and 201 are in black.
+
+Authors: Frank da Cruz and Christine M. Gianone
+Address: The Kermit Project
+         Columbia University
+         612 West 115th Street
+         New York NY 10025-7799
+         USA
+Fax:     +1 (212) 662-6442
+E-Mail:  [5]kermit-support@columbia.edu
+Web:     [6]http://www.columbia.edu/kermit/
+Or:      [7]http://www.kermit-project.org/
+Or:      [8]http://www.columbia.nyc.ny.us/kermit/
+     _________________________________________________________________
+
+  NOTICES
+
+   This document:
+          Copyright © 1997, 2002, Frank da Cruz and Christine M. Gianone.
+          All rights reserved.
+
+   Kermit 95:
+          Copyright © 1995, 2002, Trustees of Columbia University in the
+          City of New York. All rights reserved.
+
+   C-Kermit:
+          Copyright © 1985, 2002,
+          Trustees of Columbia University in the City of New York. All
+          rights reserved. See the C-Kermit [9]COPYING.TXT file or the
+          copyright text in the [10]ckcmai.c module for disclaimer and
+          permissions.
+
+   When Kerberos(TM) and/or SRP(TM) (Secure Remote Password) and/or
+          SSL/TLS protocol are included:
+          Portions Copyright © 1990, Massachusetts Institute of
+          Technology.
+          Portions Copyright © 1991, 1993 Regents of the University of
+          California.
+          Portions Copyright © 1991, 1992, 1993, 1994, 1995 by AT&T.
+          Portions Copyright © 1997, Stanford University.
+          Portions Copyright © 1995-1997, Eric Young
+          <eay@cryptosoft.com>.
+
+   For the full text of the third-party copyright notices, see
+   [11]Appendix V.
+     _________________________________________________________________
+
+  WHAT IS IN THIS FILE
+
+   This file lists changes made to C-Kermit since version 7.0 was
+   released in January 2000. Use this file as a supplement to:
+
+     * The second edition of [12]Using C-Kermit; and:
+     * The [13]C-Kermit 7.0 Update Notes. Also available in plain-text
+       form as [14]ckermit70.txt.
+
+   until the third edition of Using C-Kermit is published. We apologize
+   for the scattered documentation and will consolidate it when we are
+   able.
+     _________________________________________________________________
+
+   ADDITIONAL FILES Several other files accompany this new Kermit
+   release:
+
+   [15]ckututor.html
+          C-Kermit Tutorial (for Unix). Also distributed in Nroff form as
+          [16]ckuker.nr, the Unix C-Kermit manual page.
+
+   [17]security.htm
+          Discussion of Kermit's new authentication and encryption
+          features, updated for C-Kermit 8.0.
+
+   [18]telnet.htm
+          Detailed documentation of Kermit's Telnet client, updated for
+          C-Kermit 8.0.
+
+   [19]ftpscripts.html
+          Tutorial: Writing FTP automation scripts
+
+   [20]ckcbwr.html
+          Platform-independent C-Kermit hints and tips. Also distributed
+          in plain text form as [21]ckcbwr.txt
+
+   [22]ckubwr.html
+          Unix-specific C-Kermit hints and tips. Also distributed in
+          plain text form as [23]ckubwr.txt.
+
+   [24]ckvbwr.html
+          VMS-specific C-Kermit hints and tips. Also distributed in plain
+          text form as [25]ckvbwr.txt.
+
+   [26]ckuins.html
+          Unix C-Kermit installation instructions. Also distributed in
+          plain text form as [27]ckuins.txt.
+
+   [28]ckvins.html
+          VMS C-Kermit installation instructions. Also distributed in
+          plain text form as [29]ckvins.txt.
+
+   [30]ckccfg.html
+          Compile-time configuration options. Also distributed in plain
+          text form as [31]ckccfg.txt.
+
+   [32]ckcplm.html
+          C-Kermit Program Logic Manual. Also distributed in plain text
+          form as [33]ckcplm.txt.
+
+   [34]iksd.html
+          Internet Kermit Service Aministrators Guide for Unix.
+
+   [35]skermit.html
+          C-Kermit as an SSH Subsystem (SFTP server replacement).
+
+   [ [36]Top ] [ [37]C-Kermit ] [ [38]Kermit Home ]
+  __________________________________________________________________________
+
+CONTENTS
+
+     [39]0. WHAT'S NEW
+     [40]1. FIXES SINCE VERSION 7.0.196
+     [41]2. SSH AND HTTP 
+         [42]2.1. SSH Connections
+         [43]2.2. HTTP Connections
+            [44]2.2.1. HTTP Command Switches
+            [45]2.2.2. HTTP Action Commands
+            [46]2.2.3. HTTP Headers
+            [47]2.2.4. Secure HTTP Connections
+            [48]2.2.5. HTTP Variables
+            [49]2.2.6. The HTTP Command-Line Personality
+     [50]3. THE BUILT-IN FTP CLIENT
+         [51]3.1. Making and Managing FTP Connections
+            [52]3.1.1. Kermit Command-Line Options for FTP
+            [53]3.1.2. The FTP Command-Line Personality
+            [54]3.1.3. The FTP URL Interpreter
+            [55]3.1.4. Interactive FTP Session Establishment
+         [56]3.2. Making Secure FTP Connections
+         [57]3.3. Setting FTP Preferences
+         [58]3.4. Managing Directories and Files
+         [59]3.5. Uploading Files With FTP
+            [60]3.5.1. FTP PUT Switches
+            [61]3.5.2. Update Mode
+            [62]3.5.3. Recovery
+         [63]3.6. Downloading Files With FTP
+            [64]3.6.1. FTP GET Switches
+            [65]3.6.2. Filename Collisions
+            [66]3.6.3. Recovery
+         [67]3.7. Translating Character Sets
+            [68]3.7.1. Character Sets and Uploading
+            [69]3.7.2. Character Sets and Downloading
+         [70]3.8. FTP Command Shortcuts
+         [71]3.9. Dual Sessions
+         [72]3.10. Automating FTP Sessions
+            [73]3.10.1. FTP-Specific Variables and Functions
+            [74]3.10.2. Examples
+            [75]3.10.3. Automating Secure FTP Connections
+         [76]3.11. Advanced FTP Protocol Features  [77]4. FILE SCANNING
+    [78]5. FILE AND DIRECTORY NAMES CONTAINING SPACES
+    [79]6. OTHER COMMAND PARSING IMPROVEMENTS
+         [80]6.1. Grouping Macro Arguments
+         [81]6.2. Directory and File Name Completion
+         [82]6.3. Passing Arguments to Command Files
+         [83]6.4. More-Prompting
+         [84]6.5. Commas in Macro Definitions
+         [85]6.6. Arrow Keys
+    [86]7. NEW COMMANDS AND SWITCHES
+    [87]8. SCRIPTING IMPROVEMENTS
+         [88]8.1. Performance and Debugging
+         [89]8.2. Using Macros as Numeric Variables
+         [90]8.3. New IF Conditions
+         [91]8.4. The ON_UNKNOWN_COMMAND and ON_CD Macros
+         [92]8.5. The SHOW MACRO Command
+         [93]8.6. Arrays
+         [94]8.7. New or Improved Built-in Variables and Functions
+         [95]8.8. The RETURN and END Commands
+         [96]8.9. UNDEFINing Groups of Variables
+         [97]8.10. The INPUT and MINPUT Commands
+         [98]8.11. Learned Scripts
+         [99]8.12. Pattern Matching
+         [100]8.13. Dates and Times
+         [101]8.14. Trapping Keyboard Interruption
+    [102]9. S-EXPRESSIONS
+         [103]9.1. What is an S-Expression?
+         [104]9.2. Integer and Floating-Point-Arithmetic
+         [105]9.3. How to Use S-Expressions
+         [106]9.4. Summary of Built-in Constants and Operators
+         [107]9.5. Variables
+         [108]9.6. Assignments and Scope
+         [109]9.7. Conditional Expressions
+         [110]9.8. Extensibility
+         [111]9.9. Examples
+         [112]9.10. Differences from Algebraic Notation
+         [113]9.11.Differences from Lisp
+    [114]10. FILE TRANSFER
+    [115]11. MODEMS AND DIALING
+    [116]12. TERMINAL CONNECTION
+    [117]13. CHARACTER SETS
+    [118]14. DIALOUT FROM TELNET TERMINAL SERVERS
+    [119]15. COPING WITH BROKEN KERMIT PARTNERS
+    [120]16. NEW COMMAND-LINE OPTIONS
+    [121]17. LOGS
+
+   [ [122]Top ] [ [123]C-Kermit ] [ [124]Kermit Home ]
+  __________________________________________________________________________
+
+0. WHAT'S NEW
+
+   The Initialization and Customization Files
+          C-Kermit 8.0 now supports specification of the initialization
+          file name (path) in an environment variable, CKERMIT_INI. It
+          also relies far less than before on the initialization for
+          functioning. See [125]Section 5 of the Unix C-Kermit
+          [126]installation instructions for details. As of version
+          8.0.201, C-Kermit also executes your customization file (if you
+          have one) even if the initialization file was not found.
+          Previously, the customization file was executed by a TAKE
+          command in the initialization file (and it still is, if an
+          initialization is found).
+
+   Incompatible Changes
+          As always, we do our best to avoid changes that break existing
+          scripts. However, C-Kermit 8.0 does include a rather pervasive
+          syntax change that might alter the behavior of scripts that
+          depend on the previous behavior. As described in [127]Section
+          5, C-Kermit now accepts doublequotes in most contexts where you
+          previously had to use braces to group multiple words into a
+          single field, or to force inclusion of leading or trailing
+          blanks. Most noticeably, in C-Kermit 7.0 and earlier:
+
+  echo {this is a string}
+
+          would print:
+
+  this is a string
+
+          whereas:
+
+  echo "this is a string"
+
+          printed:
+
+  "this is a string"
+
+          In C-Kermit 8.0, both print:
+
+  this is a string
+
+          To force the doublequotes to be treated as part of the string,
+          use either of the following forms:
+
+  echo {"this is a string"}
+  echo ""this is a string""
+
+          Similarly, to force braces to be treated as part of the string:
+
+  echo "{this is a string}"
+  echo {{this is a string}}
+
+          Other incompatibilities:
+
+         1. Using the SET HOST command to make HTTP connections is no
+            longer supported. Instead, use the new HTTP OPEN command,
+            described in [128]Section 2.2.
+
+   C-Kermit 7.1 Alpha.01 (8 December 2000)
+
+     Its major new features are those listed in the [129]Table of
+          Contents: the FTP client, file scanning, command parsing and
+          scripting improvements, S-Expressions, and support for the
+          Telnet Com Port Option, plus wider availability of the
+          Kerberos, SSL/TLS, and SRP security options for secure Internet
+          connections.
+
+   C-Kermit 7.1.199 Alpha.02 (4 January 2001)
+
+          + C-Kermit now accepts [130]FTP, TELNET, and IKSD URLs as its
+            first command-line argument.
+          + Character-set translation added to the FTP client for
+            [131]filenames. 
+          + Optional [132]setting of date of incoming files by FTP [M]GET
+            from the server date.
+          + [133]FTP CHECK filename added to let FTP client check the
+            existence of a file on the server.
+          + [134]FTP GET /NAMELIST:filename added to get list of server
+            filenames into a local file.
+          + [135]FTP [M]PUT /SERVER-RENAME:template added to make server
+            rename a file as indicated by the template after it has
+            arrived completely.
+          + FTP [M]GET /SERVER-RENAME:template added to make server
+            rename a file as indicated by the template after it has been
+            sent completely.
+          + FTP [136]VDIRECTORY added for getting verbose directory
+            listings from TOPS-20.
+          + [137]FTP TYPE TENEX added for transferring 8-bit binary files
+            with PDP-10s.
+          + Added [138]automatic text/binary mode switching for FTP
+            [M]GET, based on filename patterns (e.g. *.zip, *.gz, *.exe
+            are binary; *.txt, *.c are text).
+          + [139]SET SEND I-PACKETS OFF added for coping with Kermit
+            servers that do not support I packets.
+          + A new option was added to [140]\fword() and \fsplit() for
+            parsing comma-separated lists that might contain empty
+            elements.
+          + Bug fixes including:
+               o {} or "" could not be used as expected to represent the
+                 empty string.
+               o ,- on a line by itself in a macro definition caused
+                 subsequent statements to be skipped.
+               o FTP [M]GET didn't work right if path segments were
+                 included in the filespec.
+               o FTP MGET, if interrupted, did not clear its file list.
+               o Various problems with FTP PUT /AS-NAME that nobody
+                 noticed.
+               o Some FTP messages and displays interfered with each
+                 other.
+               o Parsing of YESTERDAY, TODAY, and TOMORROW in date-time
+                 fields was broken.
+               o Automatic old-to-new dialing directory format conversion
+                 was broken on VMS.
+               o Various source-code portability problems fixed.
+          + Improvement of various HELP and SHOW messages.
+
+   C-Kermit 7.1.199 Alpha.04 (1 April 2001)
+
+          + Big changes:
+               o Changed default modem type from NONE to GENERIC.
+               o Generic dialing now sends no init string at all.
+               o Changed default terminal bytesize from 7 to 8.
+          + New features:
+               o SET SESSION-LOG TIMESTAMPED-TEXT for timestamped session
+                 log.
+          + New modem types:
+               o Conexant modem family
+               o Lucent VENUS chipset
+               o PCTel V.90 chipset
+               o Zoom V.90
+               o Zoom V.92
+          + FTP client:
+               o FTP OPEN /PASSIVE and /ACTIVE switches added.
+               o Now works with servers that that don't include path in
+                 NLST response.
+               o Fixed SEND /RECURSIVE not to follow symlinks (UNIX).
+               o SET FTP VERBOSE-MODE default is now OFF instead of ON.
+          + Kermit protocol:
+               o Fixed what I hope is the last "Receive window full"
+                 error.
+               o SET PREFIXING or SET CONTROL PREFIX now automatically
+                 sets CLEARCHANNEL OFF.
+               o Fixed incorrect report of number of files transferred at
+                 end of transfer.
+               o Fixed SEND /RECURSIVE not to follow symlinks (UNIX).
+          + UNIX:
+               o HTTP and shadow passwords enabled for SCO 5.0.6.
+               o Even with SET FILENAMES CONVERTED, spaces were still
+                 accepted in incoming filenames; now they are converted
+                 to underscores.
+               o Added support for compile-time mktemp()/mkstemp()
+                 selection.
+          + VMS:
+               o Session-log format for scripted sessions fixed.
+          + Scripting:
+               o Fixed \frdir() not to follow symlinks (UNIX).
+               o Fixed \fday() not to dump core for dates prior to 17 Mar
+                 1858.
+          + General:
+               o "Closing blah..." message upon exit could not be
+                 surpressed.
+               o Added /PAGE and /NOPAGE to DELETE switches.
+               o Added GO response for DELETE /ASK (delete all the rest
+                 without asking).
+               o Added GO response to "more?" prompt (for multi-page
+                 screen output).
+               o Updated HELP texts.
+
+   C-Kermit 7.1.199 Beta.01 (10 May 2001)
+
+          + FTP client verbosity adjustments.
+          + Bug with generic modem dialing pausing several secs fixed.
+          + SET HOST /USER:, SET LOGIN USERID, etc, fixed when given no
+            user ID.
+          + A couple \v(dm_blah) dial modifier variables added.
+          + "--version" command-line switch added.
+          + Fixed NetBSD serial-port DTR handling.
+          + Lots of syntax cleanups for Flexelint and gcc -Wall.
+          + Fixed modem-type aliases to not take precedence over real
+            names.
+          + Fixed funny treatment of doublequotes by ECHO command.
+          + Enabled SET SESSION-LOG for VMS and other non-UNIX platorms.
+          + Fixed changing direction in command history buffer.
+          + Fixed handling of IKSD URLs.
+          + Made sure DELETE prints a message if it got any errors.
+
+   C-Kermit 8.0.200 Beta.02 (28 June 2001)
+
+          + Major version number increased from 7 to 8.
+          + [141]SSH command.
+          + More-consistent Kermit protocol defaults.
+          + CONNECT idle timeout and action selection.
+          + CONNECT status variable.
+          + A way to allocate more space for filename lists.
+          + Pseudoterminal handler fixed for late-model Linuxes.
+          + Command-line option -dd for timestamped debug log.
+          + Download directory now works for external protocols too.
+          + GREP /COUNT:variable.
+          + SET ATTRIBUTE RECORD-FORMAT { OFF, ON }.
+          + Bug fixes.
+
+   C-Kermit 8.0.200 Beta.03 (9 Sep 2001)
+
+          + [142]HTTP 1.1 connections and scripting
+          + [143]ON_CTRLC macro for trapping Ctrl-C in scripts
+          + [144]Date-time parsing improvements, timezones, comparison,
+            arithmetic
+          + [145]Pattern-matching improvements
+          + FTP improvements
+          + SET EXIT HANGUP { ON, OFF }
+          + SET FILE EOF { CTRL-Z, LENGTH }
+          + ASK[Q] /TIMEOUT
+          + Bug fixes
+          + New platforms
+
+   C-Kermit 8.0.200 Beta.04 (16 Nov 2001)
+
+          + [146]New Unix man page
+          + [147]New Unix installation instructions
+          + SET TELOPT policies are now enforced on non-Telnet ports if
+            the server begins Telnet negotiations.
+          + SET TERMINAL IDLE-ACTION { TELNET-NOP, TELNET-AYT }.
+          + UUCP lockfile creation race condition fixed.
+          + Dialout, modem signals, hangup, hardware flow control, etc,
+            tested extensively on many platforms, numerous problems
+            fixed.
+          + Improved hints when dialing fails.
+          + SET STOP-BITS 2 can now be given without SET FLOW HARDWARE.
+          + Major improvements in RFC 2217 Telnet Com-Port Control.
+          + Improved ability to REDIAL a modem server port.
+          + kermit -h now shows the command name in the usage usage
+            string.
+          + kermit -h now shows ALL command-line options.
+          + kermit -s blah, where blah is a symlink, now works.
+          + --noperms command-line option = SET ATTRIBUTE PERMISSIONS
+            OFF.
+          + HTTP and HTTPS URLs now supported on the command line.
+          + An http command-line personality is now available.
+          + Initialization file streamlined to load faster, anachronisms
+            removed.
+          + Updated NEWS, INTRO, HELP text, SHOW commands. In particular,
+            see SHOW COMM, HELP SET LINE, HELP WAIT.
+          + Date/time arithmetic routines converted from floating-point
+            to integer arithmetic (internally) for greater accuracy and
+            portability.
+          + Quoted strings containing commas no longer break macro
+            execution.
+          + Dynamic Kermit file-transfer timeouts are now much more
+            aggressive.
+          + New "hot keys" to turn debug.log on/off during file transfer.
+          + Improved hints when file transfer fails.
+          + FTP CD orientation messages are now printed.
+          + -R now accepted on the FTP command line to request Recursion.
+          + -m allows Active or Passive mode to be chosen on the FTP
+            command line.
+          + -dd on the FTP command line creates a timestamped debug.log.
+          + FTP command-line security options filled in.
+          + Improved automatic text/binary mode switching for MGET.
+          + Removed spurious error messages that sometimes occur during
+            MGET.
+          + DIRECTORY, GREP, TYPE, HEAD, and TAIL now have a /OUTPUT:file
+            option.
+          + TYPE /NUMBER adds line numbers.
+          + CAT = TYPE /NOPAGE; MORE = TYPE /PAGE.
+          + GETOK ?-help fixed.
+          + \v(timestamp) (= "\v(ndate) \v(time)")
+          + \v(hour) (hour of the day, 0-23)
+          + \funix2dospath() converts a UNIX path (/) to a DOS one (\).
+          + \fdos2unixpath() converts a DOS (Windows, OS/2) path to a
+            UNIX one.
+          + \fkeywordval() parses name=value pair, allows macro keyword
+            parameters.
+          + We now make every attempt to not write passwords to the
+            debug.log.
+          + New Certficate Authority certificates file, includes the
+            Kermit Project at Columbia University so you can access our
+            IKSD securely.
+          + Secure targets improved and better documented in Unix
+            makefile.
+          + All Linux (libc and glibc) builds consolidated under "make
+            linux".
+          + HP-UX makefile targets now have consistent names.
+          + New aix50 and aix51 targets added.
+
+   C-Kermit 8.0.200 Final (12 Dec 2001)
+
+          + Remote/local-mode confusion on some platforms introduced in
+            Beta.04, fixed.
+          + Many of the makefile targets adjusted, new ones added.
+          + New "make install" target should please most people.
+          + New command: SHOW IKSD.
+          + FTP over TLS.
+          + Last-minute touchups to text messages, HELP text, etc.
+          + Enable modem-signal reading for SCO OSR5 and Unixware 7.
+          + Special superfast TRANSMIT /BINARY /NOECHO /NOWAIT mode
+            added.
+          + Fixed PBX dialing in unmarked-area-code case.
+          + Improved SHOW COMMUNICATIONS tells lockfile directory,
+            typical dialout device name.
+          + Some FTP OPEN command parsing problems fixed.
+          + Some errors in date arithmetic fixed.
+          + New command: SET TERMINAL AUTODOWNLOAD { ..., ERROR { STOP,
+            CONTINUE } }
+          + New command: HELP FIREWALL.
+          + SET MODEM HANGUP-METHOD DTR added as synomym for RS232-SIGNAL
+          + Support for secure URL protocols added: telnets:, ftps:,
+            https:.
+
+   C-Kermit 8.0.201 (8 Feb 2002)
+
+          + Installability as an [148]SSH v2 Subsystem.
+          + [149]SET LOCUS command.
+          + [150]L-versions of CD, DIR, DELETE, MKDIR, etc, to force
+            local execution.
+          + [151]USER and ACCOUNT added as synonyms for FTP USER and FTP
+            ACCOUNT.
+          + [152]SHOW VARIABLES now accepts a list of variables.
+          + Rudimentary support for [153]Caller ID when receiving phone
+            calls.
+          + Up/Down [154]Arrow-key navigation of command history buffer.
+          + [155]Automatic execution of customization file if init file
+            is missing.
+
+   C-Kermit 8.0.206 Beta.01 (11 Oct 2002)
+
+        New commands:
+
+               o ORIENTATION lists location-related variables and their
+                 values.
+               o KCD changes to special directories by their symbolic
+                 names ("kcd ?" for a list).
+               o SET CD HOME path to specify home directory for CD and
+                 KCD commands.
+               o CONTINUE given at top level is equivalent to END --
+                 handy when PROMPT'ed out of a script, to continue the
+                 script.
+
+        New switches or operands for existing commands:
+
+               o GETOK /TIMEOUT
+               o ASK, ASKQ, GETOK /QUIET (suppresses error message on
+                 timeout)
+               o COPY /APPEND now allows concatenating multiple source
+                 files into one dest file.
+               o SET TCP { HTTP-PROXY, SOCKS-SERVER } /USER, /PASSWORD.
+               o DIRECTORY command now accepts multiple filespecs, e.g.
+                 "dir a b c".
+
+        SET QUIET ON now also applies to:
+
+               o SET HOST connection progress messages.
+               o "Press the X or E key to cancel" file-transfer message.
+               o REMOTE CD response.
+               o REMOTE LOGIN response.
+
+        Improvements and new features:
+
+               o Numerous FTP client fixes and new features, listed
+                 below.
+               o C-Kermit, when in remote mode at the end of a file
+                 transfer, now prints a one-line "where" message. Control
+                 with SET TRANSFER REPORT.
+               o Unix makefile "install" target now creates an UNINSTALL
+                 script.
+               o Improved operation and performance on RFC 2217 Telnet
+                 connections.
+               o Improved CONNECT (interactive terminal connection)
+                 performance.
+               o HELP text updated for many commands.
+
+        New or fixed makefile targets:
+
+               o Solaris 9 (several variations)
+               o Concurrent PowerMAX
+               o Mac OS X 10.2
+               o FreeBSD 1.0
+               o FreeBSD 4.6, 5.0
+               o AIX 5.2, 5.3
+
+        Bugs fixed (general):
+
+               o Failure to run in VMS Batch fixed.
+               o LDIRECTORY fixed to run Kermit's built-in DIRECTORY
+                 command rather than an external one.
+               o Fixed Solaris and other SVORPOSIX builds to find out
+                 their full hostnames rather than just the "uname -n"
+                 name.
+               o Fixed some problems matching strings that start with
+                 ".".
+               o Fixed some problems matching pattern that contain
+                 {a,b,c} lists.
+               o Fixed erroneous reporting of text-mode reception as
+                 binary when sender did not report the file size
+                 (cosmetic only).
+               o Many problems with SWITCH statements fixed.
+               o Fixed SET OPTIONS DIRECTORY /DOTFILES to work for server
+                 too.
+               o Fixed DELETE to print an error message if the file was
+                 not found.
+               o Fixed SET CONTROL UNPREFIX ALL and SET PREFIXING NONE to
+                 do the same thing.
+               o Fixed bugs executing macros from within the ON_EXIT
+                 macro.
+               o \fday() and \fnday() fixed for dates prior to 17 Nov
+                 1858.
+               o Serial speed-changing bug in Linux fixed.
+               o "Unbalanced braces" script parsing errors when using
+                 \{number} fixed.
+               o "if defined \v(name)" fixed to behave as described in
+                 the book.
+               o Fixed Problems caused by LOCAL variables whose names are
+                 left substrings of macro names.
+               o The INPUT command was fixed to honor the PARITY setting.
+               o Fixed bug with COPY to existing file that is longer than
+                 source file.
+               o REINPUT command failed to strip braces/quotes around its
+                 target string.
+               o Network directory lookups didn't work for SSH
+                 connections.
+               o REMOTE SET { FILE, TRANSFER } CHARACTER-SET fixed.
+               o Closed some holes whereby an incompletely received file
+                 was not deleted when SET FILE INCOMPLETE is DISCARD,
+                 e.g. when the Kermit is hung up upon.
+               o SET XFER CHARACTER-SET TRANSPARENT fixed to do the same
+                 as SET XFER TRANSLATION OFF.
+               o SET HOST PTY (e.g. SSH) connection fixed to pass along
+                 window-size changes.
+               o C-Kermit search path for TAKE files was accidentally
+                 disabled.
+
+        FTP client bugs fixed:
+
+               o Character set translation was broken on little-endian
+                 (e.g. PC) architectures.
+               o FTP PUT /SERVER-RENAME:, /RENAME-TO:, /MOVE-TO: switches
+                 were sticky.
+               o Make SET TRANSFER MODE MANUAL apply to FTP.
+               o Make SET FILE INCOMPLETE { KEEP, DISCARD } apply to FTP.
+               o FTP MGET /UPDATE handled equal times incorrectly.
+               o FTP MGET /RECOVER fixed to ignore file dates, use only
+                 size.
+               o FTP MGET /RECOVER sometimes downloaded files it didn't
+                 need to.
+               o FTP downloads with TRANSFER DISPLAY BRIEF could give
+                 misleading error messages.
+               o FTP MGET temp file not deleted if FTP DEBUG set to OFF
+                 after it was ON.
+               o LOCUS not switched back when FTP connection is lost.
+               o Set incoming file date even if it was not completely
+                 received.
+               o FTP MGET sent SIZE and MDTM commands even when it didn't
+                 have to.
+               o FTP MGET sent SIZE and MDTM commands even when it knew
+                 they wouldn't work.
+               o FTP MGET failed if no files were selected for download.
+               o FTP MGET a* b* c* would fail to get any c*'s if no b*'s
+                 existed.
+               o Big problems canceling MGET with Ctrl-C.
+               o Some extraneous LOCUS dialogs squelched.
+               o Some inconsistencies in SET FTP FILENAMES AUTO fixed.
+               o Fixed file-descriptor pileup after multiple MGETs when
+                 using mkstemp().
+               o Fixed "mget foo", where foo is a directory name.
+
+        FTP improvements:
+
+               o New [156]FTP protocol features added (FEAT, MLSD).
+               o FTP MGET /RECURSIVE now works as expected if server
+                 supports MLSD.
+               o FTP MGET /DATES-DIFFER to download if local and remote
+                 file dates differ.
+               o FTP DATES default changed to ON.
+               o FTP MPUT, MGET /EXCEPT now allows up to 64 patterns (up
+                 from 8).
+               o Top-level SITE and PASSIVE commands added for
+                 convenience.
+               o MGET /COLLISION:APPEND /AS-NAME:newfile *.* puts all
+                 remote files into one local file.
+               o SET FTP SERVER-TIME-OFFSET for when server has wrong
+                 timezone set.
+               o Allow for alternative server interpretations of [M]MPUT
+                 /UNIQUE.
+               o SET FTP ANONOMOUS-PASSWORD lets you specify the default
+                 anonymous password.
+               o Allow "GET /RECURSIVE path/file" to force local
+                 subdirectory creation.
+               o SET FTP DISPLAY is like SET TRANSFER DISPLAY but applies
+                 only to FTP.
+               o FTP { ENABLE, DISABLE } new-protocol-feature-name.
+               o FTP MGET /NODOTFILES.
+               o Debug log now records FTP commands and responses in
+                 grep-able format.
+
+   [ [157]Top ] [ [158]Contents ] [ [159]C-Kermit ] [ [160]Kermit Home ]
+  __________________________________________________________________________
+
+1. FIXES SINCE VERSION 7.0.196 First, the changes from 7.0.196 to 7.0.197...
+Source and makefile tweaks to get successful builds on platforms that were not
+available in time for the 7.0 release:
+
+     * 4.2BSD
+     * 4.3BSD
+     * AIX 4.3
+     * AT&T 3B2 and 3B20
+     * BeOS 4.5
+     * CLIX
+     * Interactive UNIX System V/386 R3.2 V4.1.1
+     * OS-9/68000
+     * OSF/1 1.3.
+     * PS/2 AIX 1.2.1
+     * SCO OSR5.0.x
+     * SCO Xenix 2.3.4
+     * SINIX 5.41/Intel
+     * Stratus FTX
+     * Stratus VOS
+     * SunOS 4.1 with X.25
+     * Ultrix 4.2
+     * Unixware 2.0
+
+   There were no functional changes from 196 to 197.
+
+   Fixes applied after C-Kermit 7.0.197 was released:
+
+   Source code: Big flexelint and "gcc -Wall" audit and cleanup.
+
+   Configuration:
+     * Solaris RTS/CTS (hardware flow control) didn't work.
+     * BSDI RTS/CTS worked only in one direction.
+     * FreeBSD 4.0 with ncurses 5.0 broke interactive command parsing.
+     * QNX-32 build lacked -DBIGBUFOK so couldn't execute big macros.
+
+   Connections:
+     * SET HOST /PTY didn't work on some platforms.
+     * Broken SET HOST /USER:xxx /PASSWORD:yyy /ACCOUNT:zzz switches
+       fixed.
+     * Transparent printing was broken in Unix.
+     * ANSWER 0 (wait forever) didn't work.
+     * Some problems in Multitech modem command strings.
+     * Spurious "?Sorry, can't condition console terminal" errors.
+     * Disabling modem command strings by setting them to nothing broke
+       dialing.
+     * SET DIAL TIMEOUT value was usually ignored.
+     * SET DIAL METHOD PULSE didn't work.
+     * Certain modem commands, if changed, not refreshed if modem type
+       changed.
+     * SET SESSION-LOG command was missing from VMS.
+     * VMS session log format fixed for scripts.
+     * HANGUP by dropping DTR didn't work in NetBSD.
+     * SET FLOW /AUTO versus SET FLOW confusion fixed.
+     * Spurious secondary Solaris lockfile removed.
+     * SCO OSR5 DTR On/Off hangup.
+     * UUCP lockfile race condition.
+
+   Commands and scripts:
+     * Missing CAUTIOUS and FAST commands restored.
+     * Broken PTY command in late-model Linuxes fixed (API changed).
+     * Fixed off-by-one error in command recall when switching direction.
+     * Fixed recall of commands that contain '?'.
+     * COPY /SWAP-BYTES didn't work on some architectures.
+     * Various combinations of COPY switches didn't work.
+     * Various problems with COPY or RENAME with a directory name as
+       target.
+     * SHIFT didn't decrement \v(argc) if used within IF, ELSE, or SWITCH
+       block.
+     * SHIFT didn't affect the \%* variable.
+     * Divide by zero improperly handled in some \function()s.
+     * Problems with RETURN from right-recursive functions.
+     * FSEEK /LINE \%c LAST didn't work if already at end.
+     * Some buffer vulnerabilities and potential memory leaks were
+       discovered and fixed.
+     * \frdirectory() fixed not to follow symbolic links.
+     * SET EXIT WARNING OFF fixed to work when EXIT given in a script.
+     * Missing DELETE and MKDIR error message fixed.
+     * \fday() core dump for ancient dates fixed.
+
+   File transfer:
+     * SEND /COMMAND was broken.
+     * CRECEIVE was broken (but RECEIVE /COMMAND was OK).
+     * Quoting wildcard chars in filenames didn't work.
+     * Problems canceling streaming file transfers with X or Z.
+     * Problems shifting between streaming and windowing file transfer.
+     * Non-FULL file-transfer displays erroneously said STREAMING when
+       not.
+     * An active SEND-LIST prevented GET from working.
+     * SET SERVER GET-PATH interpretation of relative names like "." was
+       wrong.
+     * The MAIL command was broken.
+     * "kermit -s *" might have skipped some files.
+     * Transaction log entries were not made for external protocol
+       transfers.
+     * File count report fixed to show number of files actually
+       transferred.
+     * Fixed filename conversion to convert spaces to underscores.
+     * Made SET PREFIXING / SET CONTROL PREFIX also adjust CLEARCHANNEL.
+     * More "Receive window full" errors fixed.
+     * Broken terminal buffering after curses display in Solaris fixed.
+     * SET FILE INCOMPLETE DISCARD did not work in all cases.
+     * Packet log changed to reformat the start-of-packet character
+       printably.
+     * Dynamic timeouts could grow ridiculously large.
+
+   Character sets:
+     * Hebrew-7 translations missed the letter Tav.
+     * C1 area of CP1252 was ignored.
+     * SET TRANSFER CHARACTER-SET TRANSPARENT could give garbage
+       translations.
+     * TRANSLATE might not work on Little Endian architectures.
+     * Insufficient range checking in certain TRANSLATE operations.
+
+   The following bugs in C-Kermit 8.0.200 were fixed in 8.0.201:
+
+     * An obscure path through the code could cause the Unix version of
+       C-Kermit to dump core during its startup sequence. This happened
+       to only one person, but now it's fixed.
+     * When C-Kermit 8.0 is in Kermit server mode and the client says
+       "get blah", where blah (on the server) is a symlink rather than a
+       real file, the server unreasonably refused to send the linked-to
+       file.
+     * When C-Kermit is an FTP client and says "get foo/bar" (i.e. a
+       filename that includes one or more path segments), it failed to
+       accept the incoming file (this happened only with GET, not MGET).
+     * Array references should be case insensitive but only lowercase
+       array letters were accepted.
+     * SHOW VARIABLES dumped core on \v(sexpression) and \v(svalue).
+     * Spurious refusals of remote directory listings if the remote
+       server's date was set in the past.
+     * In AIX, and maybe elsewhere too, Kermit's COPY command always
+       failed with "Source and destination are the same file" when the
+       destination file didn't exist.
+     * The VMS version of C-Kermit did not work in Batch or when SPAWN'd.
+       To compound the problem, it also pretty much ignored the -B and -z
+       command-line options, whose purpose is to work around such
+       problems.
+     * C-Kermit 8.0 could not be built on IRIX 5.x.
+     * The C-Kermit 8.0 build for QNX6 said it was an "(unknown
+       version)".
+
+   Other fixes are listed in the [161]previous section.
+
+   [ [162]Top ] [ [163]Contents ] [ [164]C-Kermit ] [ [165]Kermit Home ]
+  __________________________________________________________________________
+
+2. SSH AND HTTP
+
+  2.1. SSH Connections
+
+     This section does not apply to [166]Kermit 95 2.0, which has its
+     own built-in SSH client, which is documented [167]SEPARATELY. 
+
+   On most UNIX platforms, C-Kermit can make SSH (Secure SHell)
+   connection by running the external SSH command or program through its
+   pseudoterminal interface. The command is:
+
+   SSH text
+          Tells Kermit to start the external SSH client, passing the
+          given text to it on the command line. Normally the text is just
+          the hostname, but it can be anything else that is acceptable to
+          the ssh client. If the command succeeds, the connection is made
+          and Kermit automatically enters CONNECT (terminal) mode. You
+          can use the SSH command to make a connection to any host that
+          has an SSH server.
+
+   Kermit's SSH command gives you all the features of Kermit on an SSH
+   connection: command language, file transfer, character-set
+   translation, scripting, and all the rest. By default, C-Kermit invokes
+   SSH with "-e none", which disables the ssh escape character and makes
+   the connection transparent for purposes of file transfer. You can,
+   however, change the SSH invocation to whatever else you might need (an
+   explicit path, additional command-line arguments, etc) with:
+
+   SET SSH COMMAND text
+          Specifies the system command that Kermit's SSH command should
+          use to invoke the external SSH client. Use this command to
+          supply a specific path or alternative name, or to include
+          different or more command-line options.
+
+   In most cases, these connections work quite well. They can be scripted
+   like any other connection, and file transfer goes as fast as, or
+   faster than, on a regular Telnet connection. In some cases, however,
+   the underlying pseudoterminal driver is a limiting factor, resulting
+   in slow or failed file transfers. Sometimes you can work around such
+   problems by reducing the Kermit packet length. Note that Kermit does
+   not consider SSH connections to be reliable, so it does not offer to
+   use streaming in Kermit protocol transfers (but you can force it with
+   SET RELIABLE or SET STREAMING if you wish).
+
+   The SSH command is like the TELNET command: it enters CONNECT mode
+   automatically when the connection is made. Therefore, to script an SSH
+   connection, use:
+
+  set host /pty ssh -e none [ other-options ] host
+  if fail ...
+
+   to make the connection.
+
+   Here's a sequence that can be used to make a connection to a given
+   host using Telnet if the host accepts it, otherwise SSH:
+
+  if not defined \%1 exit 1 Usage: \%0 host
+  set quiet on
+  set host \%1 23 /telnet
+  if fail {
+      set host /pty ssh -l \m(user) -e none \%1
+      if fail exit 1 \%1: Telnet and SSH both fail
+      echo SSH connection to \%1 successful
+  } else {
+      echo Telnet connection to \%1 successful
+  }
+
+   In SSH v2, it is possible to make an SSH connection direct to a Kermit
+   server system if the host administrator has configured the SSH server
+   to allow this; [168]CLICK HERE for details.
+
+   Since Kermit uses external ssh client software, and since there are
+   different ssh clients (and different releases of each one), the exact
+   command to be used to make an SSH/Kermit connection can vary. Here is
+   the command for the OpenSSH 3.0.2p1 client:
+
+set host /pipe ssh -e none [ -l username ] -T -s hostname kermit
+
+   Example:
+
+set host /pipe ssh -e none -l olga -T -s hq.xyzcorp.com kermit
+
+   The SSH client might or might not prompt you for a password or other
+   information before it makes the connection; this depends on your SSH
+   configuration (your public and private keys, your authorized hosts
+   file, etc). Here's a brief synopsis of the OpenSSH client command
+   syntax ("man ssh" for details):
+
+   -e none
+          This tells the SSH client to use no escape character. Since we
+          will be transferring files across the connection, we don't want
+          the connection to suddenly block because some character in the
+          data.
+
+   -l username
+          This is the username on the remote host. You can omit the -l
+          option and its argument if your local and remote usernames are
+          the same. If they are different, you must supply the remote
+          username.
+
+   -T
+          This tells the SSH client to tell the SSH server not to
+          allocate a pseudoterminal. We are not making a terminal
+          connection, we don't need a terminal, and in fact if a terminal
+          were allocated on the remote end, the connection would not
+          work.
+
+   -s ... kermit
+          This tells the SSH client to tell the SSH server to start the
+          specified subsystem ("kermit") once the connection is made. The
+          subsystem name comes after the hostname.
+
+   hostname
+          The IP host name or address of the desired host.
+
+   You might want to include other or additional ssh command-line
+   options; "man ssh" explains what they are. Here are some examples for
+   the OpenSSH 3.0.2p1 client:
+
+   -oClearAllForwardings yes
+   -oForwardAgent no
+   -oForwardX11 no
+   -oFallbackToRsh no
+          These ensure that a secure connection is used and that the
+          connection used for file transfer is not also used for
+          forwarding other things that might be specified in the
+          ssh_config file.
+
+   -oProtocol 2
+          (i.e. SSH v2) Ensures that the negotiated protocol supports
+          subsystems.
+
+   Once you have an SSH connection to a Kermit server, it's just like any
+   other connection to a Kermit server (and very similar to a connection
+   to an FTP server). You give the client file transfer and management
+   commands for the server, and the server executes them. Of course you
+   can also give the client any other commands you wish.
+
+   [ [169]SSH Kermit Server Subsystem ] [ [170]Kermit 95 Built-in SSH
+   Client ]
+     _________________________________________________________________
+
+  2.2. HTTP Connections
+
+   Hypertext Transfer Protocol, or HTTP, is the application protocol of
+   the World Wide Web (WWW), used between Web browsers (clients) and Web
+   servers. It allows a client to get files from websites, upload files
+   to websites, delete files from websites, get information about website
+   directories and files, and interact with server-side CGI scripts.
+   C-Kermit includes an HTTP client capable of both clear-text and secure
+   HTTP connections, that can do all these tasks and can be automated
+   through the Kermit scripting language.
+
+   Although C-Kermit 7.0 could make HTTP connections to Web servers, it
+   could do so only when no other connection was open, and the procedure
+   was somewhat awkward. C-Kermit 8.0 improves matters by:
+
+     * Allowing an HTTP connection to be open at the same time as a
+       regular SET LINE or SET HOST connection, and also at the same time
+       as an FTP connection ([171]Section 3);
+     * Upgrading the HTTP protocol level from 1.0 to 1.1, thus allowing
+       for persistent connections, in which a series of commands can be
+       sent on the same connection, rather than only one as in HTTP 1.0
+       (and C-Kermit 7.0);
+     * Providing for "one-shot" URL-driven HTTP operations such as GET or
+       PUT.
+     * Providing a distinct HTTP command-line personality.
+
+   Persistent HTTP connections are managed with the following commands:
+
+   HTTP [ switches ] OPEN [ security-options ] host-or-url [ port ] 
+          Opens a persistent connection to the specified host (IP host
+          name or address) on the specified port. If any switches
+          (options, listed in the next section) are included, their
+          values are saved and used for all subsequent HTTP action
+          commands on the same connection. If no port is specified, HTTP
+          (80) is used. A Uniform Resource Locator (URL, [172]RFC 1738)
+          can be given instead of a hostname (or address) and port (but
+          the URL can not include a directory/file path). The security
+          options are explained [173]below. The HTTP OPEN command
+          replaces the C-Kermit 7.0 SET HOST hostname HTTP command, which
+          no longer works with HTTP GET and related commands.
+
+   HTTP CLOSE
+          Closes any open HTTP connection and clears any saved switch
+          values.
+
+   A URL starts with a protocol name, which must be http or https in this
+   case; optionally includes a username and password; and must contain a
+   host name or address:
+
+  protocol://[user[.password]]@host[:port][URI]
+
+   HTTP is Hypertext Transfer Protocol. HTTPS is the secure (SSL/TLS)
+   version of HTTP. The TCP service port is derived from the protocol
+   prefix (so normally the ":port" field is omitted). Thus the URL
+   protocol name specifies a default TCP service port and the URL user
+   and password fields can take the place of the /USER and /PASSWORD
+   switches ([174]Section 2.2.1). The optional URI is a "compact string
+   of characters for identifying an abstract or physical resource"
+   ([175]RFC 2396), such as a file. It must begin with a slash (/); if
+   the URI is omitted, "/" is supplied. Examples:
+
+   http open http://www.columbia.edu/
+          Equivalent to http open www.columbia.edu or http open
+          www.columbia.edu http.
+
+   http open https://olga.secret@www1.xyzcorp.com/
+          Equivalent to http /user:olga /pass:secret open
+          www1.xyzcorp.com https.
+
+   Persistence is accomplished unilaterally by C-Kermit 8.0. An HTTP 1.0
+   server closes the connection after each action. Although HTTP 1.1
+   allows multiple actions on the same connection, an HTTP 1.1 server
+   tends to close the connection if it is idle for more than a few
+   seconds, to defend itself against denial-of-service attacks. But when
+   you use Kermit's HTTP OPEN command to create a connection, Kermit
+   reopens it automatically (if necessary) for each HTTP action until you
+   close it with HTTP CLOSE, regardless of the server's HTTP protocol
+   version, or how many times it closes the connection.
+
+   Firewalls can be negotiated through proxies with the following
+   commands:
+
+   SET TCP HTTP-PROXY [ host[:port] ]
+          If a host (by hostname or IP address) is specified, Kermit uses
+          it as a proxy server when attempting outgoing TCP connections
+          -- not only HTTP connections, but all TCP/IP connections,
+          Telnet and FTP included. This allows Kermit to adapt to the
+          HTTP firewall penetration method (as opposed to other methods
+          such as SOCKS4). If no hostname or ip-address is specified, any
+          previously specified Proxy server is removed. If no port number
+          is specified, the "http" service is used. This command must be
+          given before the HTTP OPEN command if a proxy is to be used or
+          canceled.
+
+   HTTP [ switches ] CONNECT host[:port]
+          Instructs the HTTP server to act as a proxy, establishing a
+          connection to the specified host (IP hostname or address) on
+          the given port (80 = HTTP by default) and to redirect all data
+          transmitted between Kermit and itself to the given host for the
+          life of the connection. This command is to be used only for
+          debugging HTTP proxy connections. If a proxy connection is
+          required, instruct Kermit to use the proxy with the SET TCP
+          HTTP-PROXY command.
+
+    2.2.1. HTTP Command Switches
+
+   HTTP switches, like all other switches, are optional. When HTTP
+   switches are included with the HTTP OPEN command, they apply
+   automatically to this and all subsequent HTTP actions (GET, PUT, ...)
+   on the same connection until an HTTP CLOSE command is given. So if you
+   include switches (or the equivalent URL fields, such as user and
+   password) in the HTTP OPEN command, you can omit them from subsequent
+   commands on the same connection. If the connection has closed since
+   your last command, it is automatically reopened with the same options.
+
+   If you include switches with an HTTP action command (such as GET or
+   PUT), they apply only to that command.
+
+   /USER:name
+          To be used in case a page requires a username for access. The
+          username is sent with page requests. If it is given with the
+          OPEN command it is saved until needed. If a username is
+          included in a URL, it overrides the username given in the
+          switch. CAUTION: Username and password (and all other
+          information, including credit card numbers and other material
+          that you might prefer to protect from public view) are sent
+          across the network in clear text on regular HTTP connections,
+          but authentication is performed securely on HTTPS connections.
+
+   /PASSWORD:text
+          To be used in case a web page requires a password for access.
+          The password is sent with page requests. If it is given with
+          the OPEN command it is saved until needed. If a password is
+          given in a URL, it overrides the one given here. CAUTION: (same
+          as for /USER:).
+
+   /AGENT:user-agent
+          Identifies the client to the server. Overrides the default
+          agent string, which is "C-Kermit" (for C-Kermit) or "Kermit-95"
+          (for Kermit 95).
+
+   /ARRAY:array-designator
+          Tells Kermit to store the response headers in the given array,
+          one line per element. The array need not be declared in
+          advance. Example: /array:&a.
+
+   /TOSCREEN
+          Tells Kermit to display any response text on the screen. It
+          applies independently of the output file specification; thus it
+          is possible to have the server response go to the screen, a
+          file, both, or neither.
+
+   /HEADER:header-item(s)
+          Used for specifying any optional headers to be sent with HTTP
+          requests.
+
+  /HEADER:tag:value
+
+          To send more than one header, use braces for grouping:
+
+  /HEADER:{{tag:value}{tag:value}...}
+
+          For a list of valid tags and value formats see [176]RFC 2616,
+          "Hypertext Transfer Protocol -- HTTP/1.1". A maximum of eight
+          headers may be specified.
+
+    2.2.2. HTTP Action Commands
+
+   HTTP actions can occur within a persistent connection, or they can be
+   self-contained ("connectionless"). A persistent HTTP connection begins
+   with an HTTP OPEN command, followed by zero or more HTTP action
+   commands, and is terminated with an HTTP CLOSE command:
+
+  http open www.columbia.edu
+  if failure stop 1 HTTP OPEN failed: \v(http_message)
+  http get kermit/index.html
+  if failure stop 1 HTTP GET failed: \v(http_message)
+  (more actions possible here...)
+  http close
+
+   A self-contained HTTP action occurs when a URL is given instead of a
+   remote file name to an HTTP action command. In this case, Kermit makes
+   the HTTP connection, takes the action, and then closes the connection.
+   If an HTTP connection was already open, it is closed silently and
+   automatically.
+
+  http get http://www.columbia.edu/kermit/index.html
+
+   Kermit's HTTP action commands are as follows. Switches may be included
+   with any of these to override switch (or default) values given in the
+   HTTP OPEN command.
+
+   HTTP [ switches ] GET remote-filename [ local-filename ]
+          Retrieves the named file from the server specified in the most
+          recent HTTP OPEN command for which a corresponding HTTP CLOSE
+          command has not been given. The filename may not include
+          wildcards (HTTP protocol does not support them). If no HTTP
+          OPEN command is in effect, this form of the HTTP GET command
+          fails. The default local filename is the same as the remote
+          name, but with any pathname stripped. For example, the command
+          http get kermit/index.html stores the file in the current local
+          directory as index.html. If the /HEADERS: switch is included,
+          information about the file is also stored in the specified
+          array (explained in [177]Section 2.2.3). All files are
+          transferred in binary mode. HTTP does not provide for
+          record-format or character-set conversion.
+
+   HTTP [ switches ] GET url [ local-filename ]
+          When HTTP GET is given a URL rather than a filename, Kermit
+          opens a connection to the designated server (closing any
+          previously open HTTP connection), gets the file, and then
+          closes the connection. If the URL does not include a filename,
+          index.html is supplied. This is the self-contained one-step
+          "connectionless" method for getting a file from a Web server.
+          The data is not interpreted; HTTP GET is like "lynx -source"
+          rather than "lynx -dump".
+
+   In the remaining HTTP action commands, the distinction between a
+   remote filename and a URL are the same as in the HTTP GET command.
+
+   HTTP [ switches ] HEAD remote-filename-or-url [ local-filename ]
+          Like GET except without actually getting the file; instead it
+          retrieves only the headers. If the /ARRAY: or /TOSCREEN switch
+          is included, there is no default local output filename but you
+          can still specify one. If neither of these switches is
+          included, the default local filename is the same as the remote
+          filename, but with any path stripped and with ".head" appended.
+          The HEAD command can be used in a script with the /ARRAY:
+          switch to retrieve information about the requested resource to
+          determine whether the resource should actually be retrieved
+          with a subsequent GET request.
+
+   HTTP [ switches ] INDEX remote-directory-or-url [ local-filename ]
+          Asks the server to send a listing of the files in the given
+          server directory. This command is not supported by most Web
+          servers. Even when it is supported, there is no standard format
+          for the listing.
+
+   HTTP [ switches ] POST [ /MIME-TYPE:type ] source-file
+          remote-path-or-url [ result-file ]
+          Sends data to a process running on the remote host; the result
+          is usually an HTML file but could be anything. The data to be
+          posted must be read from a local file (the source-file). If a
+          result file is specified, Kermit stores the server's response
+          in it.
+
+   HTTP [ switches ] PUT [ MIME-TYPE:type ] local-file [
+          remote-file-or-url [ result-file ] ]
+          Uploads a local file to the server. Only the name of a single
+          file can be given; wildcards (and group transfers) are not
+          supported by HTTP protocol. If no remote filename is given, the
+          file is sent with the same name as the local file, but with any
+          pathname stripped.
+
+   HTTP [ switches ] DELETE remote-file-or-url [ local-result-file ]
+          Asks the server to delete the specified single file. If a
+          result file is specified, it will contain any response data
+          returned by the server.
+
+   Note the limitations of HTTP protocol compared to (say) FTP or Kermit.
+   There is no command for changing directories, no standard way to get
+   file or directory lists, no way to transfer file groups by using
+   wildcard notation, etc, and therefore no good way to (say) fetch all
+   pages, descend through subdirectories, perform automatic updates, etc.
+   There is no assurrance a connection will stay open and, as noted,
+   there is no provision for data conversion between unlike platforms.
+   The data's MIME headers can be used for postprocessing.
+
+    2.2.3. HTTP Headers
+
+   Each HTTP request and response contains a set of name/value pairs
+   called headers. HTTP headers are specified in [178]RFC 2616. For
+   example, an HTTP GET request for /index.html on www.columbia.edu
+   contains the following headers:
+
+  GET /index.html HTTP/1.1
+  Host: www.columbia.edu:80
+  User-agent: C-Kermit 8.0
+  Authorization: Basic base64-encoded-username-password
+
+   These might be followed by any others specified with a /HEADERS:
+   switch:
+
+  Accept: image/gif, image/x-xbitmap, image/jpeg, *.*
+  Accept-Encoding: gzip
+  Accept-Language: en
+  Accept-Charset: iso-8859-1,utf-8
+  Cookie: cookie-data
+
+   The server sends back a short report about the file prior to sending
+   the file contents. Example:
+
+  HTTP/1.1 200 OK
+  Date: Fri, 24 Aug 2001 21:09:39 GMT
+  Server: Apache/1.3.4 (Unix)
+  Last-Modified: Mon, 06 Aug 2001 21:16:13 GMT
+  ETag: "1fa137-10d7-3b6f091d"
+  Accept-Ranges: bytes
+  Content-Length: 4311
+  Content-Type: text/html
+
+   If you want to have this information available to a Kermit script you
+   can use the /ARRAY switch to have Kermit put it in array, one line per
+   array element. Example:
+
+  set exit warning off
+  http open www.columbia.edu
+  if fail exit 1 Can't reach server
+  http /array:&a get /index.html
+  if fail exit 1 Can't get file
+  echo Header lines: \fdim(&a)
+  for \%i 1 \fdim(&a) 1 {
+      echo \%i. \&a[\%i]
+  }
+
+   Note that the "Date:" item is the current date and time; the
+   "Last-Modifed:" item is the file's modification date and time. An
+   example showing how to use this information is presented in
+   [179]Section 8.13.7.
+
+    2.2.4. Secure HTTP Connections
+
+   SSL/TLS (Secure Sockets Layer / Transport Layer Security) is the
+   protocol used to secure HTTP, SMTP, and other Internet applications.
+   See the [180]C-Kermit Reference Section 5.4 for an introduction to
+   SSL/TLS. To make a secure HTTP connection, you need:
+
+    1. A secure client (a version of C-Kermit or Kermit 95 with SSL/TLS
+       security built in). Type "check ssl" at the Kermit prompt to make
+       sure you have it.
+    2. A secure server to connect to.
+    3. The CA Root Certificate used to authenticate the server to the
+       client. (see [181]Section 15 of the security reference for an
+       introduction to certificates).
+
+   And you must make a connection to the secure HTTP port: service name
+   HTTPS, port number 443 (as opposed to service HTTP, port 80). You can
+   also make secure connections to other ports by including the /TLS or
+   /SSL switch with the HTTP OPEN command, if the host supports SSL/TLS
+   on the given port:
+
+   The quality of the SSL/TLS connection depends on the cipher suite.
+   There are several possibilities:
+
+   Anonymous cipher suite:
+          If an anonymous cipher suite is negotiated, the connection is
+          encrypted but there is no authentication. This connection is
+          subject to a Man-In-The-Middle (MITM) attack.
+
+   X.509 certificate on the server:
+          When you connect to certain secure servers, an X.509
+          certificate is returned. This certificate is issued to a
+          special hostname, something like www1.xyzcorp.com or
+          wwws.xyzcorp.com (rather than the normal www.xyzcorp.com). It
+          is signed by the host's Certificate Authority (CA). If the host
+          certificate is configured on the client, it can be used to
+          verify the certificate received from the server. If the
+          certificate it verified as authentic, a check is made to ensure
+          it has not expired and it was issued to the host you were
+          attempting to connect to. If you had asked to connect to (say)
+          www.xyzcorp.com but were given a certificate for
+          www1.xyzcorp.com, you would be prompted for permission to
+          continue.
+
+          If the verification succeeded, the connection would be
+          encrypted with one-way (server-to-client) authentication. This
+          connection is not subject to a MITM attack.
+
+          If a username and password are transmitted over this
+          connection, they are not subject to interception. However, the
+          standard risks associated with passing the password to the host
+          for verification apply; for example, if the host has been
+          compromised, the password will be compromised.
+
+   X.509 client certificate:
+          If a connection has been established with an X.509 server
+          certificate, the server can ask the client to send a
+          certificate of its own. This certificate must be verified
+          against a CA Root certificate. The certificate itself (or
+          subject info from the certificate) is used to determine the
+          authorization for the client, and if successful, the username
+          and password need not be sent to the server.
+
+   Kerberos 5:
+          Instead of using X.509 certifcates, Kerberos 5 can be used to
+          perform the authentication and key exchange. In this situation,
+          there is mutual authentication between the client and server.
+          The Kerberos 5 principal is used by the server to look up the
+          appropriate authorization data. There is no need to send
+          username and password.
+
+   An HTTP connection is made with the HTTP OPEN command:
+
+   HTTP [ switches ] OPEN [ { /SSL, /TLS } ] host [ port ] 
+          If /SSL or /TLS switches are included (these are synonyms), or
+          if the service is HTTPS or the port is 443, a secure connection
+          is attempted using the current authentication settings; see
+          HELP SET AUTHENTICATION for details ([182]Section 6.2 of the
+          security reference). If the no /SSL or /TLS switch is included
+          but the port is 443 or the service is HTTPS, a secure
+          connection is attempted. If an /SSL or /TLS switch is included
+          but a port is not specified, an SSL/TLS connection is attempted
+          on the default port (80).
+
+   Certificates are covered in the separate [183]Kermit Security
+   Reference for C-Kermit 8.0. You should let Kermit know to verify
+   certificates with the SET AUTHENTICATION TLS command. For example:
+
+   SET AUTHENTICATION TLS CRL-DIR directory
+          Specifies a directory that contains certificate revocation
+          files where each file is named by the hash of the certificate
+          that has been revoked.
+
+   SET AUTHENTICATION TLS CRL-FILE filename
+          Specifies a file that contains a list of certificate
+          revocations.
+
+   SET AUTHENTICATION TLS VERIFY-DIR directory
+          Specifies a directory that contains root CA certificate files
+          used to verify the certificate chains presented by the peer.
+          Each file is named by a hash of the certificate.
+
+   SET AUTHENTICATION TLS VERIFY-FILE filename
+          Specifies a file that contains root CA certificates to be used
+          for verifying certificate chains.
+
+   SET AUTHENTICATION TLS VERIFY OFF
+          Tells Kermit not to require a certificate and accept any
+          certificate that is presented regardless of whether it is
+          valid.
+
+   There are many other options; see the security document for details.
+
+   Now suppose you need need to fetch the file denoted by the following
+   URL:
+
+  https://myuserid:mypassword@wwws.xyzcorp.com/clients/info/secret.html
+
+   Once you have set up the handling of certificates as desired, you can
+   use the following Kermit commands:
+
+  http /user:myuserid /password:mypassword open www1.xyzcorp.com https
+  if success {
+      http get /clients/info/secret.html
+      http close
+  }
+
+   As another example, let's say that you have a web form you need to
+   populate with three fields: red,white and blue.
+
+  <FORM ACTION="http://www.xyzcorp.com/cgi-bin/form.cgi" METHOD="POST">
+  <INPUT NAME="Red">
+  <INPUT NAME="White">
+  <INPUT NAME="Blue">
+  </FORM>
+
+   You can handle this with the HTTP POST command. The data to be posted
+   is stored in the local file data.txt.
+
+  Red=seven stripes&White=six stripes&Blue=fifty stars
+
+   and the response from the server will be stored into response.txt.
+
+  http open www.xyzcorp.com http
+  if success {
+    http /array:c post data.txt /cgi-bin/form.cgi response.txt
+    http close
+  }
+
+   In this scenario, the Common Gateway Interface (CGI) sends a response
+   whether it succeeds or fails in a script-dependent manner. The script
+   can either report success and enclose the response data; or it might
+   send a 302 Found error which indicates that the "Location:" header
+   should be used to determine the URL at which the data can be found.
+
+    2.2.5. HTTP Variables
+
+   \v(http_code)
+          The HTTP protocol code number of the most recent server reply,
+          e.g. 404 for "not found".
+
+   \v(http_connected)
+          1 when an HTTP connection is open, 0 when there is no HTTP
+          connection.
+
+   \v(http_host)
+          If an HTTP connection is open, the hostname:port, e.g.
+          www.columbia.edu:80; otherwise, empty.
+
+   \v(http_message)
+          Server error message, if any, from most recent HTTP command.
+
+   \v(http_security)
+          A list of the security parameters and values for the current
+          connection, if any. Empty if the connection is not to a secure
+          server, or there is no connection.
+
+   To display all the HTTP variables at once, type SHOW VAR HTTP:
+
+  C-Kermit> http open www.columbia.edu
+  C-Kermit> http get lkjlkjlkjlkj 
+  C-Kermit> sho var http
+   \v(http_code) = 404
+   \v(http_connected) = 1
+   \v(http_host) = www.columbia.edu:80
+   \v(http_message) = Not Found
+   \v(http_security) = NULL
+  C-Kermit>
+
+    2.2.6. The HTTP Command-Line Personality
+
+   If you invoke C-Kermit with the name "http" or "https", you can use a
+   special set of HTTP-specific command-line options. You can do this by
+   creating a symbolic linke "http" or "https" to the C-Kermit 8.0
+   executable, or by having a separate copy of it called "http" or
+   "https". Here's the usage message ("http -h"):
+
+  Usage: ./http host [ options... ]
+   -h             This message.
+   -d             Debug to debug.log.
+   -S             Stay (issue command prompt when done).
+   -Y             Do not execute Kermit initialization file.
+   -q             Quiet (suppress most messages).
+   -u name        Username.
+   -P password    Password.
+   -g pathname    Get remote pathname.
+   -p pathname    Put remote pathname.
+   -H pathname    Head remote pathname.
+   -l pathname    Local path for -g, -p, and -H.
+   -z opt[=value] Security options...
+      cert=file   Client certificate file
+      certsok     Accept all certificates
+      key=file    Client private key file
+      secure      Use SSL
+      verify=n    0 = none, 1 = peer , 2 = certificate required
+
+   The "host" argument is the name of a Web host, e.g. www.columbia.edu.
+   The action options are -p, -g, and -H. If you give an action option,
+   Kermit does the action and then exits. If you give a host without an
+   action option, Kermit makes an HTTP connection to the host and then
+   gives you the C-Kermit prompt. Here's a simple example that fetches a
+   publicly readable Web page:
+
+  http www.columbia.edu -g kermit/index.html
+
+   If you need to access a website for which a username and password are
+   required, you can supply them on the command line with -u and -P. If
+   you include a username but omit the password, Kermit prompts you for
+   it:
+
+  http www.columbia.edu -u olga -p kermit/index.html -l index.html
+  Password:
+
+   Note that when PUT'ing files to websites, you have to supply both the
+   -p (remote pathname) and -l (local path) options.
+
+   If your version of Kermit is built with SSL/TLS security, you can also
+   use the -z option to make secure HTTP (https) connections.
+
+   Finally, as noted in [184]Section 16, you can also give a URL instead
+   of a host name and options.
+
+   [ [185]Top ] [ [186]Contents ] [ [187]C-Kermit Home ] [ [188]Kermit
+   Home ]
+  __________________________________________________________________________
+
+3. THE BUILT-IN FTP CLIENT
+
+     3.1.  [189]Making and Managing FTP Connections
+     3.2.  [190]Making Secure FTP Connections
+     3.3.  [191]Setting FTP Preferences
+     3.4.  [192]Managing Directories and Files
+     3.5.  [193]Uploading Files With FTP
+     3.6.  [194]Downloading Files With FTP
+     3.7.  [195]Translating Character Sets
+     3.8.  [196]FTP Command Shortcuts
+     3.9.  [197]Dual Sessions
+     3.10. [198]Automating FTP Sessions
+     3.11. [199]Advanced FTP Protocol Features
+
+   Earlier versions of C-Kermit and K95 included an FTP command, but it
+   simply invoked an external FTP client. Now, by popular demand, Kermit
+   includes its own built-in FTP client that offers the following
+   advantages over traditional FTP clients (and its previous interface to
+   them):
+
+     * Any of Kermit's built-in [200]security methods can be used to
+       establish and conduct secure FTP sessions with [201]FTP servers
+       that support these methods. (Security modules can be subject to
+       export restrictions.)
+     * Kermit's FTP client uses "passive mode" by default to avoid
+       blockage by firewalls and network address translators. Of course
+       active mode can be chosen too when needed.
+     * [202]Character sets can be translated as part of the transfer
+       process even when the FTP server does not support character-set
+       translation, including to/from the new Internet standard
+       international character set, [203]Unicode UTF-8. This includes
+       both the file's name and (for text files only) its contents.
+     * All of C-Kermit's [204]file-selection mechanisms are available:
+       size, date, name patterns and lists, exception lists, etc.
+     * [205]Atomic file movement capabilities are provided (delete, move,
+       or rename files automatically after successful transfer).
+     * The correct file type, "ascii" (i.e. text) or binary, is chosen
+       automatically for each file (explained in [206]Section 4), and any
+       mixture of text and binary files can be sent in a single
+       operation, even across platforms.
+     * Update mode ("don't bother transferring files that didn't change
+       since last time") and recovery (resumption of an interrupted
+       transfer from the point of failure) are available in both
+       directions.
+     * When uploading files from UNIX to UNIX, the file's permissions can
+       be preserved if desired.
+     * Recursive directory-tree PUTs are supported between any two
+       platforms that have tree-structured file systems. Recursive GETs
+       are supported between like platforms if the server cooperates and
+       between like or unlike platforms if the server supports MLSD
+       ([207]Section 3.11).
+     * When receiving files, all of Kermit's file collision actions are
+       available: backup, update, refuse, rename, etc.
+     * Multi-file transfers can be interrupted on a per-file basis,
+       automatically skipping to the next file.
+     * FTP sessions are [208]fully scriptable.
+     * An entire FTP session (connect, login, CD, upload or download,
+       logout) can be specified on the command line without using a
+       script.
+     * All of Kermit's logging options and formats are available to keep
+       an accurate and complete record of each connection and file
+       transfer, and to aid in troubleshooting.
+     * All of Kermit's file-transfer display options are available
+       (fullscreen, brief, CRT, serial, none).
+
+   And best of all:
+     * Kermit doesn't give you those annoying per-file prompts every time
+       you start a multi-file transfer without remembering to give a
+       "prompt" command first :-).
+
+   [ [209]Top ] [ [210]FTP Top ] [ [211]FTP Client Overview ] [ [212]FTP
+   Script Tutorial ] [ [213]C-Kermit Home ] [ [214]Kermit Home ]
+     _________________________________________________________________
+
+  3.1. Making and Managing FTP Connections
+
+   Each copy of Kermit can have one FTP connection open at a time. FTP
+   connections are independent of regular terminal connections; a
+   terminal connection (serial or network via SET LINE, DIAL, SET HOST,
+   TELNET, etc) may be, but need not be, open at the same time as an FTP
+   connection, and terminal connections can also be closed, and new
+   connections opened, without interfering with the FTP connection (and
+   vice versa). Thus, for example, Kermit can have an FTP connection and
+   a TELNET connection open to the same host simultaneously, using the
+   TELNET connection (e.g.) to send mail or take other desired actions as
+   various FTP actions complete. Of course, each copy of Kermit can do
+   only one thing at a time, so it can't (for example) transfer a file
+   with FTP and another file with Kermit protocol simultaneously.
+
+   A Kermit FTP session can be established by [215]command-line options,
+   by [216]URL, or by [217]interactive commands.
+
+    3.1.1. Kermit Command-Line Options for FTP
+
+   The new command-line option '-9' (sorry, we're out of letters) can be
+   used when starting C-Kermit, telling it to make an FTP connection:
+
+  kermit -9 hostname
+
+   or if a non-default FTP port is needed:
+
+  kermit -9 hostname:port
+
+   You can also specify the username on the command line with the -M ("My
+   User ID") option that was already there for other connection types:
+
+  kermit -9 hostname -M olga
+
+   If you specify the username on the command line, Kermit uses it when
+   making the connection and does not prompt you for it (but it does
+   prompt you for the password if one is required).
+
+   Once the connection is made, you get the regular Kermit prompt, and
+   can give interactive commands such as the ones described below. When
+   you give a BYE command, Kermit closes the session and exits, just as a
+   regular FTP client would do. If you don't want Kermit to exit when you
+   give a BYE command, include the -S ("Stay") option on the command
+   line.
+
+   Other Kermit command-line options that are not specific to non-FTP
+   connections should affect the FTP session in the expected ways; for
+   example, -i and -T force binary and text mode transfers, respectively.
+
+   File transfers can not be initiated on the "kermit -9" command line;
+   for that you need to use Kermit's FTP personality (next section) or
+   you can use URLs ([218]Section 3.1.3).
+     _________________________________________________________________
+
+    3.1.2. The FTP Command-Line Personality
+
+   If you want to replace your regular FTP client with C-Kermit, you can
+   make a link called "ftp" to the C-Kermit binary (or you can store a
+   copy of the C-Kermit binary under the name "ftp"). When C-Kermit is
+   invoked with a program name of "ftp" (or "FTP", case doesn't matter),
+   it assumes the command-line personality of the regular FTP client:
+
+  ftp [ options ] hostname [ port ]
+
+   In this case the options are like those of a regular FTP client:
+
+  -d  Debug: enables debug messages and creates a debug.log file.
+  -n  No autologin: Kermit should not send your user ID automatically.
+  -t  Packet trace: accepted but is treated the same as -d.
+  -v  Verbose: accepted but ignored (operation is verbose by default).
+  -i  Not interactive: accepted but ignored.
+
+   and the hostname can also be a URL (explained in [219]Section 3.1.3).
+   To specify a non-default TCP port for the FTP server, include the port
+   number or name after the hostname.
+
+   There are also some bonus options that allow you to execute an entire
+   FTP session from the shell command line, as long as you don't include
+   the -n option. These are not available with regular FTP clients, and
+   at least one of these options (-g) conflicts with UNIX ftp (where -g
+   means "no globbing", which does not apply to Kermit), and some of them
+   (like the options above) also conflict with regular Kermit
+   command-line options:
+
+  -m mode      = "passive" (default) or "active"
+  -Y            Don't execute the Kermit initialization file [1]
+  -q            Quiet, suppresses all but error messages [1]
+  -S            Stay, don't exit automatically [1]
+  -A            Autologin anonymously [2]
+  -u name       Username for autologin [2] (synonym: -M [1])
+  -P password   Password for autologin (see cautions below) [2]
+  -D directory  cd after autologin [2]
+  -b            Binary mode [2]
+  -a            Text ("ascii") mode [2] (synonym: -T [1])
+  -R            Recursive (works with -p) [4]
+  -p files      Files to put (upload) after autologin [2] (synonym: -s [1])
+  -g files      Files to get (download) after autologin [3]
+
+   [1] Same as Kermit, not available in regular FTP clients.
+   [2] Conflicts with Kermit, not available in regular FTP clients.
+   [3] Same as Kermit, conflicts with regular FTP clients.
+   [4] Conflicts with Kermit, available in some FTP clients.
+
+   Fancier options such as restart, character-set translation, filename
+   collision selection, automatic move/rename/delete, etc, are not
+   available from the command line; for these you can use the commands
+   described in the following sections. The -R option might also work
+   with -g (GET) but that depends on the server.
+
+   The following security options are also available, explained in
+   [220]Section 3.2:
+
+  -k realm      Kerberos 4 realm [4]
+  -f            Kerberos 5 credentials forwarding [4]
+  -x            autoencryption mode [4]
+  -c cipher     SRP cipher type [4]
+  -H hash       SRP encryption hash [4]
+  -z option     Security options [4]
+
+   If you include -A or specify a name of "anonymous" or "ftp", you are
+   logged in anonymously and, in the absence of -P, Kermit automatically
+   supplies a password of "user@host", where "user" is your local user
+   ID, and "host" is the hostname of the computer where Kermit is
+   running. If you do not include -p or -g, Kermit enters command mode so
+   you can type commands or execute them from a script.
+
+   If you include -p or -g, Kermit attempts to transfer the specified
+   files and then exits automatically at the end of the transfer unless
+   you also included -S (Stay). It uses the "brief" file transfer display
+   (one line per file) unless you include the -q option to suppress it.
+
+   When uploading files with -p, Kermit switches automatically between
+   text and binary mode for each file.
+
+   When downloading, you can either specify a particular mode (text or
+   binary) to be used for all the files, or you can let Kermit select the
+   type for each file automatically, based on its name (see [221]Sections
+   3.5 and [222]3.6 for greater detail). In UNIX be sure to quote any
+   wildcard characters to prevent the shell from expanding them, as shown
+   in the examples just below. Filename collisions are handled according
+   Kermit's FILE COLLISION setting (if specified in your Kermit
+   customization file; otherwise the default, which is BACKUP).
+
+   It should go without saying that the -P option should be used with
+   caution. In addition to the well-known risks of transmitting plaintext
+   passwords over the Internet, in this case the password also echos to
+   the screen if you type it, and can be seen in ps and w listings that
+   show the user's currently active command and command-line arguments.
+   Thus command-line FTP sessions are most appropriate for secure or
+   anonymous connections (those that do not require passwords).
+
+   Here's an example in which you download the latest C-Kermit "tarball"
+   from the Columbia University FTP archive:
+
+  ftp -A kermit.columbia.edu -bg kermit/archives/ckermit.tar.gz
+
+   This assumes that "ftp" is a symbolic link to C-Kermit. It logs you in
+   anonymously and gets the ckermit.tar.gz file in binary mode from the
+   kermit/archives directory.
+
+   Here's a slightly more ambitious example that illustrates CD'ing to
+   the desired server directory to get a group of files in text mode (in
+   this case the C-Kermit source files):
+
+  ftp -A kermit.columbia.edu -D kermit/f -ag "ck[cuw]*.[cwh]" makefile
+
+   In this case we CD to the kermit/f directory so we don't have to
+   include it in each file specification, and we quote the ck[cuw]*.[cwh]
+   specification so the shell doesn't expand it, since we have to pass it
+   as-is to the server. Note also that the quotes don't go around the
+   entire file list; only around each file specification that needs to be
+   quoted.
+
+   Here's one more example, that uploads a debug log file in binary mode
+   to the Kermit incoming directory (as we might ask you to do when
+   following up on a problem report):
+
+  ftp -A kermit.columbia.edu -D kermit/incoming -bp debug.log
+
+   In this case the -D option is required to tell the server where to put
+   the incoming file.
+
+   Unless the -Y option is included, your Kermit initialization file
+   (.mykermrc in UNIX, K95.INI in Windows) is executed before the command
+   line options, so you can set any FTP-related preferences there, as
+   described in the subsequent sections.
+     _________________________________________________________________
+
+    3.1.3. The FTP URL Interpreter
+
+   If Kermit is invoked with either its regular personality (as "kermit")
+          or its FTP personality (as "ftp"), you can also give a URL
+          (Universal Resource Locator) instead of a hostname and options,
+          with or without a username and password:
+          ftp ftp://user:password@host/path
+          ftp ftp://user@host/path
+          ftp ftp://@host/path   (or ftp://:@host/path)
+          ftp ftp://host/path
+          kermit ftp://host/path
+
+   If the FTP personality is used, the service must be "ftp". In all
+   cases, a hostname or address must be included. If a user is included
+   but no password, you are prompted for the password. If a path
+   (filename) is included:
+     * If "@" is included without a user, Kermit prompts for the username
+       and password.
+     * If no user and no "@" are included, "anonymous" is used.
+     * GET is assumed.
+
+   If no path (and no action options) are included, an interactive FTP
+          session is started, as in this example:
+          ftp ftp://kermit.columbia.edu
+
+   If a path is included, but a username is not included, "anonymous" is
+   used and an appropriate user@host password is supplied automatically.
+   If authentication is successful, Kermit attempts to GET the file
+   indicated by the path or, if the path is the name of a directory, it
+   asks the server for a directory listing. In both cases, Kermit
+   disconnects from the server and exits after the operation is complete
+   (unless you have included the -S option on the command line).
+
+   Here's an example that gets a listing of the Kermit directory at the
+          Kermit ftp site:
+          ftp ftp://kermit.columbia.edu/kermit/
+
+   This example gets the top-level READ.ME file from the same directory:
+          ftp ftp://kermit.columbia.edu/kermit/READ.ME
+
+   Here's the same example, but requesting a text-mode transfer:
+          ftp -T ftp://kermit.columbia.edu/kermit/READ.ME
+          This illustrates that you can mix command-line options and URLs
+          if you desire.
+
+   Here's an example that logs in as a (fictitious) real user to get a
+          file:
+          ftp ftp://olga@ftp.xyzcorp.com/resume.txt
+          The password is not included, so Kermit prompts for it.
+
+   This scheme allows Kermit to be used as the FTP helper of other
+   applications, such as Web browsers, with all its advantages over other
+   FTP clients (especially the ones that are built in to most Web
+   browsers), e.g. that it can be given wildcards, and it can pick text
+   and binary mode automatically for each file.
+
+   HINT: suppose somebody sends you an FTP URL in email, or you see it in
+   some text. If your terminal screen supports copy/paste, copy the url,
+   and then at the shell prompt type "kermit", a space, and then paste
+   the URL, e.g.:
+
+  $ kermit ftp://alpha.greenie.net/pub/mgetty/source/1.1/mgetty1.1.27-O
+
+   "$ is the shell prompt; the part you type is underlined, the rest is
+   pasted in. Kermit does the rest.
+     _________________________________________________________________
+
+    3.1.4. Interactive FTP Session Establishment
+
+   As you read this and the following sections, bear in mind that any
+   command that can be given at the prompt can also be used in a script
+   program. Kermit's script programming language is the same as its
+   interactive command language. [223]CLICK HERE if you would like to
+   learn a bit more about script writing.
+
+   An FTP session is established with the FTP OPEN command:
+
+   FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ switches ] [ port ]
+          Opens an FTP connection to the given host on the given port
+          and, if FTP AUTOLOGIN is ON, also logs you in to the server,
+          prompting for username and password if necessary. If no port is
+          specified, the regular FTP protocol port (21) is used. The OPEN
+          keyword is optional (unless the hostname conflicts with one of
+          the FTP command keywords, which you can list by typing "ftp
+          ?").
+
+   The hostname can be an IP host name, numeric IP address, or if you
+   have a network directory active (SET NETWORK DIRECTORY; see Chapter 6
+   of [224]Using C-Kermit), an entry name in the directory. In the latter
+   case, if the given hostname matches exactly one entry, the associated
+   name or address is used; if it matches more than one, Kermit cycles
+   through them until one is found that can be opened; if it matches
+   none, then the hostname is used as-is. If a directory is active but
+   you want to bypass directory lookup, include an "=" sign at the
+   beginning of the hostname, and/or use a numeric IP address.
+
+   When an FTP connection is opened, the default file-transfer mode is
+   set to binary if the client and server platforms are alike (e.g. both
+   of them are some kind of UNIX), and to text ("ascii") if they are not
+   alike. This has no particular effect for uploading since Kermit
+   automatically switches between text and binary mode for each file, but
+   might be important for downloading. The connection is also set to
+   Stream mode and File structure. Record- or page-oriented file
+   transfers are not supported by C-Kermit's FTP client.
+
+   The optional FTP OPEN switches are:
+
+   /ANONYMOUS
+          Logs you in anonymously, automatically supplying username
+          "anonymous" and user@host as the password, based on your local
+          user and host names.
+
+   /NOLOGIN
+
+          Overrides SET FTP AUTOLOGIN ON for this connection only.
+
+   /USER:name
+          Uses the given username to log you in, thus avoiding the Name:
+          prompt.
+          Overrides SET FTP AUTOLOGIN OFF for this connection only.
+
+   /PASSWORD:text
+          Uses the given text as your password, thus avoiding the
+          Password: prompt. This switch is not recommended for use in
+          script files, which would be a security risk.
+
+   /ACCOUNT:text
+          Uses the given text as your account (or secondary password,
+          depending on the requirements of the server; most servers do
+          not require or accept an account name). If an account is not
+          supplied, you are not prompted for one.
+
+   /PASSIVE
+          Opens the connection in passive mode. Passive mode is the
+          default in Kermit's FTP client, unlike in most others, since it
+          works better through firewalls. The /PASSIVE and /ACTIVE
+          switches apply only to the connection that is being opened, and
+          do not affect the global FTP PASSIVE-MODE setting.
+
+   /ACTIVE
+          Opens the connection in active mode. Use this switch if the
+          server does not support passive mode, or use the command SET
+          FTP PASSIVE-MODE OFF.
+
+   /NOINIT
+          Added in C-Kermit 8.0.201.   Tells C-Kermit not to send REST,
+          STRU, FEAT, and MODE commands to the server when the connection
+          is opened, since these have been reported to cause confusion in
+          certain servers.
+
+   When a username or password is missing, a prompt is issued at the
+   controlling terminal and you must type the response; the response can
+   not be scripted. Use the switches to avoid prompts, or one of the
+   secure authentication methods described in the next section, or see
+   [225]SET FTP AUTOLOGIN and the [226]FTP USER and similar commands
+   described later in this section.
+
+   Examples:
+
+  ftp open kermit.columbia.edu /anonymous  ; Open and log in anonymously
+  ftp kermit.columbia.edu /anonymous       ; The OPEN keyword can be omitted
+  ftp xyzcorp.com                          ; Open and maybe prompt for username
+  ftp xyzcorp.com /user:olga               ; Open and log in as olga
+  ftp testing.abccorp.com 449              ; Specify a special TCP port number
+  ftp testing.abccorp.com /user:olaf /password:secret 449
+
+   The FTP OPEN command succeeds if a connection was opened to the server
+   (even if the given username and password were not valid) and fails
+   otherwise (see [227]Section 3.8 for details).
+
+   When your FTP session is complete, you can terminate it as follows:
+
+   FTP BYE
+          Closes the FTP connection if one was open. The FTP prefix can
+          be omitted if no other connection is open at the same time (see
+          [228]Section 3.8 for details). If a connection log is active,
+          an FTP record is written to it. If Kermit was started with the
+          -9 command-line option or with its FTP command-line
+          personality, and the -S (Stay) option was not given, AND there
+          is no other active connection, the FTP BYE command also exits,
+          just as it does on a regular FTP client. Synonyms: FTP CLOSE,
+          FTP QUIT (but if the FTP prefix is omitted from QUIT, this
+          becomes the regular Kermit QUIT command, which is equivalent to
+          EXIT; i.e. it closes the connection and exits from Kermit).
+
+   The following commands can be used to achieve greater control over the
+   connection and login process:
+
+   SET FTP ANONYMOUS-PASSWORD text
+          Allows you to choose the password text to be sent automatically
+          by Kermit when you open an FTP connection with the /ANONYMOUS
+          switch.
+
+   SET FTP AUTOLOGIN { ON, OFF }
+          If you give this command prior to opening an FTP connection, it
+          controls whether Kermit tries to log you in automatically as
+          part of the connection process. Normally ON, which means the
+          username and password are sent automatically (and prompted for
+          if they are not yet known). When OFF, FTP OPEN connects to the
+          server without logging in. OFF is equivalent to the -n
+          command-line option when using Kermit's FTP command-line
+          personality.
+
+   FTP USER name [ password [ account ] ]
+          Used to log in to an FTP server to which a connection has been
+          made without autologin, or when autologin failed. If the
+          password is furnished on the command line, it is used;
+          otherwise you are prompted for a password. An account may also
+          be furnished if required by the server; it is not required by
+          Kermit and is not prompted for if omitted. Synonyms: USER, FTP
+          LOGIN.
+
+   FTP ACCOUNT text
+          Sends an account name to a server that supports accounts. If
+          the server does not support accounts, an error response occurs.
+          If the server does support accounts, the account is accepted if
+          it is valid and rejected if it is not. The account might be
+          used for charging purposes or it might be a secondary password,
+          or it might be used for any other purpose, such as an access
+          password for a particular disk. Servers that support accounts
+          might or might not allow or require the account to be sent
+          prior to login; usually it is sent after login, if at all.
+          Synonym: ACCOUNT.
+
+   Example:
+
+set ftp autologin off                  ; One thing at a time please
+ftp xyzcorp.com                        ; Try to make the connection
+if fail exit 1 FTP connection failed   ; Check that it was made
+ftp user olga secret                   ; Now log in to the server
+if fail exit 1 FTP login failed        ; Check that it worked
+ftp account 103896854                  ; Login OK - send account
+if fail echo WARNING - FTP ACCT failed ; Warn if problem
+...                                    ; (have session here)
+bye                                    ; Log out and disconnect
+
+   The following commands are used to control or get information about
+   the FTP connection. Any particular FTP server does not necessarily
+   support all of them.
+
+   FTP RESET
+          Terminates a user session but leaves the connection open,
+          allowing a new login via FTP USER.
+
+   FTP IDLE [ number ]
+          Most FTP servers automatically log you out and and disconnect
+          your session if there has been no activity for a certain amount
+          of time. Use this command to ask the server to set its idle
+          limit to the given number of seconds. Omit the number to ask
+          the server to inform you of its current idle limit.
+
+   FTP STATUS [ filename ]
+          Asks the FTP server to send information about the current
+          session. The result is a free-format report that might include
+          server identification, username and login time, FTP protocol
+          settings, and file-transfer statistics. If a filename is given,
+          the server is supposed to send detailed information about the
+          file.
+
+   FTP SYSTEM
+          Asks the FTP server to identify its operating system (Listed in
+          Internet Assigned Numbers, Operating System Names). Examples:
+          UNIX, VMS, VM/CMS, WINDOWS-NT. Unfortunately many variations
+          are allowed (e.g. LINUX-2.0, LINUX-2.2, FREEBSD, ULTRIX, etc,
+          instead of UNIX; WINDOWS-NT-3, WINDOWS-NT-3.5, WINDOWS-NT-3.51,
+          WINDOWS-NT-4, etc). The report might also include other
+          information like "Type L8", "Type I", or "Type A", indicating
+          the file-transfer mode.
+
+   FTP HELP [ keyword [ keyword [ ... ] ]
+          Asks the server to list the commands it supports. The response
+          is usually cryptic, listing FTP command mnemonics, not the
+          commands used by the client (since the server has no way of
+          knowing anything about the client's user interface). For
+          example, the PUT command is STOR in FTP protocol. If a keyword
+          is given, which should be an FTP protocol command,
+          slightly-more- detailed help is given about the corresponding
+          command (if the FTP server supports this feature). Examples:
+          "ftp help", "ftp help stor".
+
+   FTP SITE text
+          (Advanced) Sends an FTP SITE (site-specific) command. Usually
+          this means that the FTP server is asked to run an external
+          command with the given arguments. You might be able to find out
+          what SITE commands are available by sending "ftp help site" to
+          the server, but in general the availability of and response to
+          SITE commands is (not surprisingly) site specific.
+
+   FTP QUOTE text
+          (Advanced) Sends an FTP command in FTP protocol format. Use
+          this command to send commands to the server that the FTP client
+          might not know about.
+
+   SHOW FTP
+          Lists client (Kermit) FTP settings and information. Also SHOW
+          CONNECTION, SHOW COMMUNICATIONS.
+
+   HELP FTP [ keyword ]
+          Asks Kermit to list and describe its built-in FTP commands.
+
+   HELP SET FTP [ keyword ]
+          Asks Kermit to list and describe its built-in SET FTP commands.
+
+   [ [229]Top ] [ [230]FTP Top ] [ [231]C-Kermit Home ] [ [232]Kermit
+   Home ]
+     _________________________________________________________________
+
+  3.2. Making Secure FTP Connections
+
+   Also see: [233]Accessing IBM Information Exchange with Kermit.
+
+   In the previous section, you can see several examples of traditional
+   insecure authentication: username and password sent across the network
+   in clear text. Of course this is bad practice on at least two counts:
+   (1) storing passwords in files (such as script files) gives access to
+   the target systems to anybody who can obtain read access to your
+   scripts; and (2) sending this information over the network leaves it
+   open to interception by network sniffers or compromised hosts.
+
+   Because of the increasing need for security on the Internet, FTP
+   servers are beginning to appear that offer secure forms of
+   authentication, in which no information is sent over the network that
+   would allow anyone who intercepts it to usurp your identity and gain
+   your access rights.
+
+   Kermit provides an equivalent form of FTP security for each type of
+   IETF standard security implemented in Telnet. These include
+   GSSAPI-KERBEROS5, KERBEROS4, Secure Remote Password (SRP), and
+   Transport Layer Security (SSL and TLS). It does not presently include
+   SSL tunneling nor any form of SSH v1 or v2. When Kermit is built with
+   the necessary libraries, secure FTP connections are attempted by
+   default, in which all connections are authenticated and the command
+   and data channels are private.
+
+   The use of authentication and encryption for FTP connections can be
+   adjusted with the commands listed below, which are available only if
+   your version of Kermit was built with the corresponding security
+   options and libraries:
+
+   SET FTP AUTHTYPE { AUTOMATIC, GSSAPI-KRB5, KERBEROS4, SRP, SSL, TLS }
+          Specifies an ordered list of authentication methods to be
+          attempted when AUTOAUTHENTICATION is ON. The default list is:
+          GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL. If none of the
+          selected methods are supported by the server, an insecure login
+          is used as a fallback. Note, by the way, that SSL or TLS can be
+          used to secure an anonymous connection.
+
+   SET FTP AUTOAUTHENTICATION { ON, OFF }
+          Tells whether authentication should be negotiated by the FTP
+          OPEN command. Default is ON. Use SET FTP AUTOAUTHENTICATION OFF
+          to force a clear-text, unencrypted connection to FTP servers
+          (such as the one at the Kermit FTP site) that normally would
+          try to negotiate secure authentication and encryption.
+
+   SET FTP AUTOENCRYPTION { ON, OFF }
+          Tells whether encryption (privacy) should be negotiated by the
+          FTP OPEN command, which can happen only if secure
+          authentication is also negotiated. Default is ON.
+
+   SET FTP AUTOLOGIN { ON, OFF }
+          Tells Kermit whether to try logging in automatically when you
+          make an FTP connection, as opposed to letting you do it "by
+          hand" with the FTP USER command.
+
+   SET FTP COMMAND-PROTECTION-LEVEL { CLEAR, CONFIDENTIAL, PRIVATE, SAFE
+          }
+          Determines the level of protection applied to the command
+          channel:
+
+  CLEAR         Data is sent in plaintext and not protected against tampering.
+  CONFIDENTIAL  Data is encrypted but not protected against tampering.
+  PRIVATE       Data is encrypted and is protected against tampering.
+  SAFE          Data is sent in plaintext but protected against tampering.
+
+          The default is PRIVATE.
+
+   SET FTP CREDENTIAL-FORWARDING { ON, OFF }
+          Tells whether end-user credentials are to be forwarded to the
+          server if supported by the authentication method (GSSAPI-KRB5
+          only). This is often required to allow access to distributed
+          file systems (e.g. AFS.)
+
+   SET FTP DATA-PROTECTION-LEVEL { CLEAR, CONFIDENTIAL, PRIVATE, SAFE }
+          Tells what level of protection is applied to subsequent data
+          channels. The meanings of the protection-level keywords are the
+          same as for SET FTP COMMAND-PROTECTION-LEVEL. The default is
+          PRIVATE.
+
+   SET FTP SRP CIPHER name
+          Specifies the cipher to be used for encryption when SRP
+          authentication is in use. The list of possible choices is
+          computed based on the capabilities of the local SRP library and
+          includes NONE plus zero or more of the following:
+
+  BLOWFISH_ECB        CAST5_ECB          DES_ECB          DES3_ECB
+  BLOWFISH_CBC        CAST5_CBC          DES_CBC          DES3_CBC
+  BLOWFISH_CFB64      CAST5_CFB64        DES_CFB64        DES3_CFB64
+  BLOWFISH_OFB64      CAST5_OFB64        DES_OFB64        DES3_OFB64
+
+          The default is DES3_ECB.
+
+   SET FTP SRP HASH name
+          Specifies the hash to be used for data protection when SRP
+          authentication is in use. The choices are MD5 and SHA. The
+          default is SHA.
+
+   Command-line options:
+
+   -k name
+          Specifies the realm to be used with Kerberos 4 authentication
+          (= SET AUTH K4 REALM name).
+
+   -f
+          Enables forwarding of Kerberos 5 credentials to the host when
+          using GSSAPI authentication (= SET AUTH K5 FORWARDABLE ON).
+
+   -x
+          Enables autoencryption (= SET FTP AUTOENCRYPTION ON).
+
+   -c cipher
+          Specifies the kind of cipher to be used for encryption with SRP
+          authentication. Equivalent to SET FTP SRP CIPHER, with the same
+          choices. If this option is not given, CAST5_CBC is used.
+
+   -H hash
+          Specifies the hash to be used for encryption with SRP
+          authentication. Equivalent to SET FTP SRP HASH, with the same
+          choices. If this option is not given, SHA is used.
+
+   -z debug
+          Turns on SSL/TLS debugging.
+
+   -z secure
+          Requires secure connection.
+
+   -z certsok
+          Says to accept all certificates without checking validity.
+
+   -z verify=n
+          Sets certificate verification mode to the given number, n:
+            0 = no verification
+            1 = verify certificate if presented
+            2 = require verification of certificate
+
+   -z cert=filename
+          Specifies a file containing a client certificate to be
+          presented to the FTP server.
+
+   -z key=filename
+          Specifies a file containing a private key matching the client
+          certificate.
+
+   -z !krb4
+          (nokrb4) Disables the use of Kerberos 4.
+
+   -z !gss
+   -z nogss
+          Disables the use of GSSAPI - Kerberos 5.
+
+   -z !srp
+   -z nosrp
+          Disables use of SRP.
+
+   -z !ssl
+   -z nossl
+          Disables the use of SSL.
+
+   -z !tls
+   -z notls
+          Disables the use of TLS.
+
+   Caution: If your FTP connection is secured via AUTH TLS, it is not
+   possible to interrupt a file transfer. This is a limitation of all
+   known FTP servers that support AUTH TLS.
+
+   Note that when using certain security methods, such as SSL or TLS, you
+   may be prompted to confirm or verify certain actions or conditions,
+   for example, whether to accept self-signed certificates. This can
+   interfere with unattended operation of scripts; see [234]Section 3.10.
+
+   [ [235]Top ] [ [236]FTP Top ] [ [237]C-Kermit Home ] [ [238]Kermit
+   Home ]
+     _________________________________________________________________
+
+   3.3. Setting FTP Preferences FTP preferences can be set globally and
+   persistently with the commands in the following sections; many of
+   these can also be overridden on a per-command basis with switches that
+   have the same name.
+
+    3.3.1. Logs, Messages, and Other Feedback
+
+   You can control the amount of feedback received from your FTP session
+   with the commands in this section. First, you can create a log of your
+   FTP transfers with the following commands:
+
+   SET TRANSACTION-LOG { VERBOSE, FTP, BRIEF }
+          Selects the log format. VERBOSE is the default, and is
+          described in [239]the manual. FTP chooses a WU-FTPD format, the
+          same as is used by the popular FTP server. BRIEF creates
+          per-file records in comma-separated-list format. For greater
+          detail, see [240]Section 4.17 of the [241]C-Kermit 7.0 Update
+          Notes.
+
+   LOG TRANSACTIONS filename
+          Records FTP (or Kermit, or any other protocol) uploads and
+          downloads in the given file using the format selected by the
+          most recent SET TRANSACTION-LOG command, if any, or else the
+          default format.
+
+   FTP screen messages and displays are controlled by the following
+   commands:
+
+   SET TRANSFER DISPLAY { FULLSCREEN, CRT, SERIAL, BRIEF, NONE, OFF }
+          FTP transfers use Kermit's normal file-transfer display styles.
+          Use this command to choose the desired format; the default on
+          most platforms is FULLSCREEN. The display is automatically
+          disabled if Kermit is running in the background or in batch.
+          BRIEF is always used for command-line initiated transfers
+          (unless suppressed by -q). While a file-transfer is in
+          progress, you can interrupt it in the normal Kermit way by
+          typing one of the following keys or key combinations:
+            X - Cancel current file but go on to the next one (if any).
+            Z - Cancel the entire transfer.   Ctrl-L or Ctrl-W - Refresh
+          the file-transfer display (if any).
+
+   SET FTP DISPLAY { FULLSCREEN, CRT, SERIAL, BRIEF, NONE, OFF }
+          Like SET TRANSFER DISPLAY, but applies only to FTP connections,
+          and does not affect Kermit- or other protocol file transfers.
+
+   SET QUIET { ON, OFF }
+          This command applies to Kermit in general, not just FTP. OFF by
+          default; when ON, it surpresses most messages from most
+          commands as well as the file-transfer display.
+
+   SET FTP PROGRESS-MESSAGES { ON, OFF }
+          Tells whether Kermit should print locally-generated feedback
+          messages for each non-file-transfer command. ON by default.
+
+   SET FTP VERBOSE-MODE { ON, OFF }
+          Tells whether to display all responses from the FTP server. OFF
+          by default. This shows all responses to all commands, except
+          when the file-transfer display is active, and unless you have
+          SET QUIET ON. When OFF, responses are shown only for commands
+          such as FTP PWD whose purpose is to display a response.
+
+   SET FTP DEBUG { ON, OFF }
+          Tells whether local client debugging information should be
+          displayed. OFF by default. When ON, the commands that are sent
+          to the server are shown, as well as its responses (even if
+          VERBOSE-MODE is OFF), plus additional informational messages
+          are printed regarding the progress of secure operations. Also,
+          the temporary file created by the [242]MGET command is not
+          deleted so you can see what's in it.
+
+   Set all of these to OFF when silent running is desired.
+
+    3.3.2. Operational Preferences
+
+   FTP DISABLE new-protocol-feature-name
+   FTP ENABLE new-protocol-feature-name
+          Explained in [243]Section 3.11.
+
+   SET FTP AUTOLOGIN { ON, OFF }
+          If you give this command prior to opening an FTP connection, it
+          controls whether Kermit tries to log you in automatically as
+          part of the connection process. Normally ON, which means the
+          username and password are sent automatically (and prompted for
+          if they are not yet known). When OFF, FTP OPEN connects to the
+          server without logging in. OFF is equivalent to the -n
+          command-line option when using Kermit's FTP command-line
+          personality. See [244]Section 3.1.4 for usage.
+
+   SET FTP PASSIVE-MODE { ON, OFF }
+          ON by default, to avoid random TCP port assignment for data
+          connections, which can prevent FTP protocol from working
+          through firewalls and network address translators (for more on
+          these topics, see the [245]Kermit security reference. Set to
+          OFF in case the FTP server does not support passive mode, or in
+          case the client has problems with it (it has been observed, for
+          example, that when using passive mode, the SCO XENIX 2.3.4
+          TCP/IP stack hangs in the connect() call forever). Synonyms:
+          PASSIVE [ ON ], PASSIVE OFF, PASV [ ON ], PASV OFF.
+
+   SET FTP SEND-PORT-COMMANDS { ON, OFF }
+          This command determines whether the FTP client sends a new PORT
+          command to the server when accepting incoming data connections
+          (as when not using passive mode.) When PASSIVE-MODE is OFF and
+          SET SEND-PORT is OFF, the port that was originally specified is
+          reused. This is the default behavior for normal FTP clients but
+          it is not compatible with many firewalls.
+
+   SET FTP CHARACTER-SET-TRANSLATION { ON, OFF }
+          Whether to translate character sets when transferring files
+          with FTP (explained in [246]Section 3.7). OFF by default.
+
+   SET FTP SERVER-CHARACTER-SET name
+          Tells Kermit the character set used by the FTP server, UTF-8 by
+          default ([247]Section 3.7).
+
+   SET FTP SERVER-TIME-OFFSET delta-time
+          Tells Kermit to apply the given [248]delta time to file
+          timestamps provided by the server for its files; for use when
+          (for example) the server does not have its timezone set
+          correctly.
+
+   SET FTP ERROR-ACTION { PROCEED, QUIT }
+          When transferring a group of files with FTP, and an error
+          occurs with one of the files, Kermit normally goes on the next
+          file. Use SET FTP ERROR-ACTION to QUIT to make Kermit stop the
+          transfer immediately and fail if an error occurs with any
+          single file in the group. Example: you have given Kermit a list
+          of files to send, and one of the files can not be found, or
+          read permission is denied. Note that cancelling a file by
+          typing 'X' during transfer is not considered an error (if you
+          want to cancel the entire transfer, type 'Z' or Ctrl-C).
+
+   SET FTP PERMISSIONS { AUTO, ON, OFF }
+          When uploading files with PUT or MPUT, this tells whether
+          Kermit should send each file's permissions. The default is OFF,
+          which means not to send permissions, in which case the uploaded
+          file's permissions are set by the FTP server according to its
+          own criteria. ON means to send them, AUTO means to send them
+          only if the client (Kermit) and server are on like platforms
+          (e.g. both UNIX). This command has no effect when downloading,
+          since the FTP protocol does not include a way for the server to
+          inform the client of a file's permissions. Also see [249]FTP
+          PUT /PERMISSIONS. Note that setting permissions after uploading
+          is likely to work (correctly or at all) only when the client
+          and server platforms are alike (e.g. both of them are some form
+          of UNIX). Also note that Windows files don't have permissions.
+          Also see [250]FTP CHMOD.
+
+   SET FTP DATES { ON, OFF }
+          When downloading files with GET or MGET, this tells whether
+          Kermit should try to set the received file's date from the
+          server's date. FTP DATES is ON by default. Note, however, that
+          FTP protocol does not allow date preservation when uploading.
+          So at best, SET FTP DATES ON can work only when downloading,
+          and then only when the server agrees to furnish file dates.
+
+   SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }
+          When uploading (sending) files, this tells whether to convert
+          outbound filenames to "common form". This means allowing only
+          one period in a name, uppercasing any lowercase letters,
+          replacing spaces by underscores, etc. AUTOMATIC is the default,
+          meaning LITERAL when client and server are the same type of
+          system (e.g. UNIX) and CONVERTED otherwise. Special case: if
+          the setting is AUTOMATIC and the client is not UNIX and the
+          server identifies itself as UNIX, Kermit uses a less-strict
+          form of conversion, in which lowercase letters are not
+          uppercased and the filename can contain any number of periods,
+          but spaces are still converted to underscore. When receiving,
+          conversion generally means to change all-uppercase names to
+          lowercase and spaces to underscore.
+
+   SET FTP UNIQUE-SERVER-NAMES { ON, OFF }
+          Applies only to uploads. Tells the server to create new, unique
+          names for incoming files that have the same names as existing
+          files. OFF by default, in which case the server overwrites
+          existing files with new files of the same name. When ON, the
+          server uses its own built-in method for creating new names for
+          incoming files; for example, appending a period (.) and a
+          number to the name. CAUTION: Use this option only if you do not
+          need to refer to the file after it is uploaded, since FTP
+          protocol provides no mechanism for the client to find out what
+          name was assigned by the server.
+
+   SET FTP COLLISION { ... }
+          When downloading, what to do if an incoming file has the same
+          name as an existing file. Options are the same as for SET FILE
+          COLLISION. If this command is not given, Kermit's regular FILE
+          COLLISION setting is used. If this command is given, it
+          overrides the FILE COLLISION setting for FTP transfers only.
+          See [251]Section 3.6.2 for details.
+
+   SET FTP TYPE { TEXT, BINARY, TENEX }
+          Changes the default transfer mode. When sending (uploading)
+          files, this command has no effect unless you disable automatic
+          text/binary mode switching ([252]Section 4) with SET FILE SCAN
+          OFF or SET TRANSFER MODE MANUAL. When receiving (downloading)
+          files, this command establishes the transfer mode to be used
+          when a filename does not match any of Kermit's text or binary
+          filename patterns, unless you use SET FTP
+          GET-FILETYPE-SWITCHING or SET TRANSFER MODE MANUAL to disable
+          automatic switching, in which case, this command establishes
+          the transfer mode for all downloaded files. In all cases,
+          however, the FTP TYPE can be overridden in any GET or PUT
+          command by including a /TEXT (/ASCII), /BINARY, or /TENEX
+          switch. The FTP TYPE is independent of the Kermit FILE TYPE
+          setting. TENEX is used for sending 8-bit binary files to 36-bit
+          platforms such as TOPS-10, TOPS-20, and TENEX, and getting them
+          back again. Synonym: ASCII = TEXT. Note: there is also an FTP
+          TYPE command, which does what SET FTP TYPE does but also sends
+          a TYPE command to the server immediately if the given type is
+          different from the current one.
+
+   If you want want specific FTP preference settings to be in effect for
+   all your Kermit FTP sessions, put the desired SET FTP commands in your
+   Kermit customization file (~/.mykermrc in UNIX, K95CUSTOM.INI in
+   Windows).
+
+   [ [253]Top ] [ [254]FTP Top ] [ [255]C-Kermit Home ] [ [256]Kermit
+   Home ]
+     _________________________________________________________________
+
+  3.4. Managing Directories and Files
+
+   In Kermit, commands for directory and file management can refer to:
+
+     * The local computer
+     * A remote computer when you have a connection to a Kermit server or
+       IKSD.
+     * A remote computer when you have a connection to an FTP server.
+
+   (There can also be an HTTP connection, but the commands in this
+   section don't apply to HTTP connections.)
+
+   Thus in general, each such command comes in three forms:
+
+    1. With no prefix in C-Kermit 8.0.200, it refers to the local
+       computer (CD, DIR, etc). In C-Kermit 8.0.201 and later, however,
+       the "locus" switches to automatically to the remote FTP server
+       when you make an FTP connection (see the SET LOCUS description
+       [257]Section 7); thus C-Kermit 8.0.201 acts almost exactly like a
+       regular FTP client when it has an FTP connection, yet still acts
+       like itself on other kinds of connections.
+    2. With the REMOTE prefix, it is for a Kermit server (REMOTE CD,
+       REMOTE DIR).
+    3. With the FTP prefix, it's for an FTP server (FTP CD, FTP DIR).
+    4. Also see [258]Section 3.8, which explains "R-commands" and
+       "L-commands".
+
+   Kermit's FTP file and directory management commands are as follows.
+   When an R-command is included in the Synonyms list, be sure to read
+   [259]Section 3.8 about rules for use of R-commands.
+
+   FTP CD [ directory ]
+          Tells the FTP server to change its default (working) directory
+          to the one given, which usually must be expressed in the syntax
+          of the server platform (UNIX, VMS, etc). If the directory is
+          not specified, the result depends on the FTP server -- it might
+          complain that the command is illegal, or it might change to
+          your original login directory. Synonyms: FTP CWD (Change
+          Wording Directory); RCD.
+
+   FTP CDUP
+          Tells the FTP server to change its default (working) directory
+          to the parent directory of its current one (equivalent to
+          "cd .." in UNIX, or "cd [-]" in VMS). Synonyms: RCDUP, FTP UP.
+
+   FTP PWD
+          Asks the FTP server to report ("print") its current working
+          directory. Synonym: RPWD.
+
+   FTP MKDIR directory
+          Asks the FTP server to create the directory whose name is
+          given. In general, the name must be in the syntax of the
+          server's file system, and it must be either absolute (a full
+          pathname) or relative to the server's current (working)
+          directory. This command fails if the directory can't be created
+          for any reason, including that it exists already. Synonym:
+          RMKDIR.
+
+   FTP RMDIR directory
+          Asks the FTP server to remove the directory whose name is
+          given. The rules are the same as for MKDIR, plus in most cases,
+          the server will not remove any directory unless it is empty.
+          Synonym: RRMDIR.
+
+   FTP DIRECTORY [ filespec ] [ redirectors ]
+          Tells the FTP server to send a directory listing of the
+          specified files. If no filespec is given, the server lists all
+          files in its current working directory. The results are in
+          whatever format the server chooses to send them. You can use
+          UNIX-like redirectors to send the listing to a file or a
+          pipeline, exactly as with the regular Kermit client/server
+          REMOTE DIRECTORY command ([260]Using C-Kermit, Chapter 11).
+          Synonym: RDIRECTORY. Examples:
+
+    ftp dir                           ; Show listing of all files on screen
+    ftp dir *.txt                     ; List *.txt files on screen
+    ftp dir *.txt > somefile          ; Put listing in somefile
+    ftp dir *.txt >> somefile         ; Append listing to somefile
+    ftp dir *.txt | sort > somefile   ; Put sorted listing in somefile
+    ftp dir | more                    ; Runs list through "more"
+    ftp dir | sort | more             ; Runs list through "sort" and "more"
+
+   FTP VDIRECTORY [ filespec ] [ redirectors ]
+          "Verbose" directory. This is an alternative FTP DIRECTORY
+          command primarily for use with DECSYSTEM-20 (TOPS-20) FTP
+          servers, which send only filenames when given a DIRECTORY
+          command; the VDIRECTORY command makes them also send file
+          sizes, dates, and attributes.
+
+   FTP CHECK filespec
+          Asks the FTP server whether the given file exists or, if the
+          filespec contains wildcards, if any files match, and this
+          command succeeds or fails accordingly.
+
+   FTP MODTIME filename
+          Asks the FTP server, via the not-yet-standard FTP MDTM command,
+          to send the modification date and time of the given file. The
+          response should be a numeric string in the format:
+          yyyymmddhhmmssxxxxx... where yyyy is the year, mm is the month,
+          dd is the day, hh is the hour (0-23), mm is the minute, ss is
+          the second, and xxx... is the optional fraction of the second
+          (0 or more digits). The date and time is expressed in UTC (GMT,
+          Zulu, Zero-Meridian). The result is available programmatically
+          in the [261]\v(ftp_message) variable, and is understandable by
+          Kermit's date-time switches and functions. For example, suppose
+          we want to upload all local files that are newer than a
+          particular file on the server:
+
+  C-Kermit> ftp modtime signpost
+  C-Kermit> echo \v(ftp_message)
+  20010807113542.014
+  C-Kermit> ftp mput /after:\v(ftp_message)GMT *
+
+          Note that we must append "GMT" to the date-time string to let
+          the /AFTER switch know the time is GMT rather than local.
+
+   FTP SIZE filename
+          Asks the FTP server to send the size (in bytes) of the given
+          file. The result might vary depending on whether the current
+          FTP TYPE is binary or text ("ascii"). For a reliable byte
+          count, do FTP TYPE BINARY first. The result is available
+          programmatically in the [262]\v(ftp_message) variable.
+
+   FTP CHMOD permissions filename
+          Tells the FTP server to set the permissions (protection) of the
+          given file to the ones given. The permissions and filename must
+          be given in whatever syntax is required by the server. Example
+          (for a UNIX-based FTP server):
+
+  ftp chmod 664 oofa.txt
+
+          Not all servers support this command. For non-UNIX-based
+          servers, you might need to use FTP QUOTE or FTP SITE and the
+          appropriate platform-specific FTP server command.
+
+   FTP UMASK [ number ]
+          This command is probably specific to UNIX-based servers; it
+          sets the UNIX "umask", which is the default permissions mask
+          for new (in this case, incoming) files. Crudely put, the UNIX
+          umask is an octal representation of a binary number in in which
+          a 1 bit stands for a permission bit that must be 0, and a 0 bit
+          stands for a permission bit that can be 0 or 1 depending on
+          other factors, such as the permissions of the parent directory.
+          Example: "umask 007" requires that new files are created
+          without read/write/execute world permission. If the number is
+          not specified, the server's current umask is reported.
+
+   FTP RENAME filename newname
+          Asks the FTP server to rename the file whose name is "filename"
+          to "newname". Works only for one file; can not be used with
+          wildcards. The server's interpretation of "newname" can vary
+          (in some cases it must be a filename, in others perhaps it can
+          also be a directory name, in which case if the filename denote
+          a regular file, the file might be moved to the given
+          directory). Some servers might allow files to be renamed
+          ("moved") between physical disks or partitions, others might
+          not. Synonym: RRENAME.
+
+   FTP DELETE [ switches ] filespec [ filespec [ ... ] ]
+          Tells the FTP server to delete the file or files listed. Each
+          file specification may, but need not, contain wildcard
+          characters to match multiple files. File specifications and
+          wildcard syntax must be those of the server. Any file
+          specifications that contain spaces must be enclosed in braces
+          or doublequotes. FTP DELETE switches are:
+
+ /ERROR-ACTION:  /FILENAMES:     /NOBACKUPFILES  /QUIET
+ /EXCEPT:        /LARGER-THAN:   /NODOTFILES     /NOPAGE
+ /PAGE           /RECURSIVE      /SMALLER-THAN:
+
+          When used with FTP DELETE, the /RECURSIVE switch deletes files
+          but not directories, and furthermore depends on the server
+          providing recursive file lists, which is not the normal
+          behavior. For further details, see the decriptions of these
+          switches in [263]Section 3.6. Synonyms: FTP MDELETE (Kermit
+          makes no distinction between DELETE and MDELETE); RDELETE.
+
+   FTP TYPE { TEXT, BINARY, TENEX }
+          Tells the FTP server to change its file-transfer type to the
+          one given, immediately. See [264]SET FTP TYPE for details.
+
+   [ [265]Top ] [ [266]FTP Top ] [ [267]C-Kermit Home ] [ [268]Kermit
+   Home ]
+     _________________________________________________________________
+
+  3.5. Uploading Files With FTP
+
+   Uploading means sending files from the client (Kermit) to the FTP
+   server. The basic command for uploading files with FTP is PUT:
+
+   FTP PUT [ switches ] [ filespec [ as-name ] ]
+          Uploads (sends) the file or files that match the file
+          specification, which may include wildcards, to the server. If
+          no filespec is given, the names of files to send are taken from
+          the /LISTFILE: file, if any, otherwise from the SEND-LIST, if
+          any. Unless you go out of your way to prevent it, Kermit
+          determines the transfer mode (text or binary) for each file
+          automatically, and switches automatically on a per-file basis.
+          If an as-name is given, the file is sent under that name
+          instead of its own (if an as-name is given with a wildcard
+          filespec, the result is a bit more complicated, and is
+          explained later in this section).
+
+   Unlike normal FTP clients, Kermit does not prompt you by default (or
+   at all) for each file; it just sends them, just as it does with Kermit
+   protocol. The filespec can be a literal filename or a Kermit pattern,
+   described in:
+
+  [269]http://www.columbia.edu/kermit/ckermit70.html#x4.9
+
+   Kermit patterns are equivalent to C-Shell patterns and provide a fair
+   amount of flexibility in selecting which files to send, which is
+   augmented by the file-selection switches presented in [270]Section
+   3.5.1.
+
+   FTP MPUT [ switches ] filespec [ filespec [ ... ] ]
+          FTP MPUT is just like FTP PUT except it allows you to give more
+          than one file specification, and it does not allow an as-name
+          in the file list. However, as-names can be given to either PUT
+          or MPUT with the /AS-NAME: switch.
+
+   If a PUT or MPUT command results in one file being uploaded, it
+   succeeds if the file is uploaded completely and fails otherwise. If
+   more than one file is selected for upload, success or failure depends
+   on the [271]FTP ERROR-ACTION setting; if it is PROCEED (the default
+   setting), then the [M]PUT command succeeds if at least one of the
+   files was completely uploaded, and fails otherwise, If FTP
+   ERROR-ACTION is QUIT, the [M]PUT command succeeds if all selected
+   files were uploaded successfully, and fails if any file failed.
+
+   FTP uploads may be interrupted just like Kermit uploads. While the
+   transfer is in progress, type:
+
+  X to interrupt the current file and go on to the next file.
+  Z to cancel the current file and all remaining files.
+  ^C (Control-C): Like Z, but might act more quickly.
+
+   MPUT may be used as in regular FTP clients, but it is not required to
+   send multiple files; in Kermit it is required only if you want to give
+   multiple file specifications. Examples:
+
+  ftp put oofa.txt               ; Send a single file oofa.txt
+  ftp put oofa.txt budget.txt    ; Send single file oofa.txt as budget.txt
+  ftp put *.txt                  ; Send all *.txt files
+  ftp mput *.txt                 ; Send all *.txt files (same as "put *.txt")
+  ftp mput *.txt foo.bar         ; Send all *.txt files plus foo.bar
+
+   The distinction between PUT and MPUT is important only when more than
+   one filespec is given, just like the distinction between Kermit SEND
+   and MSEND:
+
+  ftp put oofa.txt budget.txt    ; Send oofa.txt AS budget.txt
+  ftp mput oofa.txt budget.txt   ; Send oofa.txt AND budget.txt
+
+   If the source file specification includes any path segments, for
+   example:
+
+  put /tmp/oofa.txt
+  put subdir/another/andanother/oofa.txt
+
+   the path portion is stripped from the filename that is sent to the
+   server. However, if an as-name contains a path, it is retained.
+   Examples:
+
+  ftp put /usr/doc/oofa.txt      ; Send as "oofa.txt".
+  ftp put oofa.txt /tmp/oofa.txt ; Send as "/tmp/oofa.txt"
+
+   The latter example sends the file oofa.txt from your current local
+   directory to the server's /tmp directory. This works only if the
+   server uses the same directory notation that you used in the as-name
+   AND the given directory already exists on the server AND if you have
+   write access to it.
+
+   Use caution when uploading from a case-sensitive file system, such as
+   UNIX, to a file system that is not case sensitive, such as Windows or
+   VMS. If you have two files in UNIX, AA and aa and upload both of them,
+   the second one will overwrite the first. The only way around this
+   provided by FTP protocol is its "unique server names" feature (SET FTP
+   UNIQUE-SERVER-NAMES or the /UNIQUE switch described below).
+     _________________________________________________________________
+
+    3.5.1. FTP PUT Switches
+
+   FTP PUT and MPUT are similar in format and behavior to the regular
+   Kermit SEND and MSEND commands, and they allow most of the same
+   optional switches:
+
+C-Kermit>ftp put ? Filename, or switch, one of the following:
+ /after:                 /larger-than:           /rename-to:
+ /array:                 /listfile:              /server-character-set:
+ /as-name:               /local-character-set:   /server-rename-to:
+ /before:                /move-to:               /simulate
+ /binary                 /nobackupfiles          /smaller-than:
+ /command                /nodotfiles             /tenex
+ /delete                 /nofollowlinks          /text
+ /dotfiles               /not-after:             /transparent
+ /error-action:          /not-before:            /type:
+ /except:                /permissions:           /update
+ /filenames:             /quiet                  /unique-server-names
+ /filter:                /recover
+ /followlinks            /recursive
+
+   Since most of these switches are common to Kermit's SEND and MSEND
+   commands, they described only briefly here. For greater detail see:
+
+     [272]http://www.columbia.edu/kermit/ckermit70.html#x1.5 (explanation
+   of switches)
+     [273]http://www.columbia.edu/kermit/ckermit70.html#x4.7
+   (file-transfer switches)
+
+   First the file-selection switches:
+
+   /AFTER:date-time
+   /BEFORE:date-time
+   /NOT-AFTER:date-time
+   /NOT-BEFORE:date-time
+          Only send those files modified on or after or before the given
+          date and time. These switches can be combined to select files
+          modified between two date/times. Various date-time formats are
+          accepted; if the date-time contains spaces, it must be enclosed
+          in braces or doublequotes. See
+          [274]http://www.columbia.edu/kermit/ckermit70.html#x1.6 and
+          [275]Section 8.13 of this document for details about date-time
+          formats. Examples:
+
+  ftp put /after:{1 jan 2000 0:00:00} *
+  ftp put /after:-5days *
+
+   /LARGER-THAN:number
+   /SMALLER-THAN:number
+          Only send files larger (smaller) than the given number of bytes
+          (octets). These switches can be combined to select files in a
+          certain size range.
+
+   /TYPE:{TEXT,BINARY}
+          Only send files that are the given type, which is determined
+          for each file just before sending it by file scanning. BINARY
+          includes TENEX; if you have included a /TENEX switch, or
+          previously given a [SET] FTP TYPE TENEX command, binary files
+          are sent in TENEX, rather than BINARY mode.
+
+   /[NO]DOTFILES
+          [Don't] include files whose names begin with dot (.). By
+          default, such files are not included unless your filespec
+          explicitly mentions them.
+
+   /NOBACKUPFILES
+          Don't include files whose names end with .~nnn~, where nnn is a
+          number, e.g. oofa.txt.~27~. These are backup files created by
+          Kermit, EMACS, and other applications. By default, backup files
+          are included.
+
+   /NOFOLLOWLINKS
+          (UNIX only) Skip over symbolic links rather than following them
+          (default). This applies to wildcard and/or recursive [M]PUTs;
+          if a single filename is given, and it happens to be a symbolic
+          link, the file it points to is sent.
+
+   /FOLLOWLINKS
+          (UNIX only) Always follow (resolve) symbolic links, even in
+          wildcard or recursive [M]PUTs. Use with caution. Watch out for
+          circular links, endless loops, etc.
+
+   /EXCEPT:pattern
+          Exception list -- don't send files whose names match the given
+          pattern. See [276]Section 1.5.4 of the [277]C-Kermit 7.0 Update
+          Notes for details. If you want to exclude a directory from a
+          recursive [M]PUT, use /EXCEPT:{dirname/*}.
+
+   /RECURSIVE
+          Sends the desired files from the current (or given) directory,
+          plus all directories beneath it, including empty directories,
+          replicating the directory structure on the server. No special
+          capabilities are required in the server, but of course your
+          login ID on the server must have the appropriate access and
+          permission to create directories. Recursive PUTs work not only
+          between like platforms (e.g. UNIX to UNIX) but also between
+          unlike ones (e.g. UNIX to VMS or Windows), in which case
+          text-file format differences are handled by Kermit's automatic
+          text/binary mode switching ([278]Section 4) and character-set
+          translation ([279]Section 3.7). Synonym: /SUBDIRECTORIES.
+
+   /UPDATE
+          Send only files that have changed since last time ([280]Section
+          3.5.2).
+
+   /ARRAY:arrayname
+          The "file" to be sent is an array, or a segment of one, rather
+          than a real file. In this case the other selection switches
+          don't apply. The array contents are sent in text mode, and each
+          array element is treated as a line. Example:
+
+  ftp put /as-name:array.txt /array:&a
+
+          (or, to send a segment of the array, /array:&a[100:199]). If
+          you don't include an /AS-NAME, a name of "_array_x_" is used
+          (where x is the array letter). If you include this switch, most
+          other switches are meaningless and ignored.
+
+   /COMMAND
+          The "file" to be sent is the standard output of a command,
+          rather than a real file. It is sent in text or binary mode
+          according to the prevailing FTP TYPE, which can be overridden
+          with a /TEXT or /BINARY switch. Example: Example:
+
+  ftp put /command /as-name:{userlist} {finger | sort -r}
+
+   /LISTFILE:filename
+          Tells Kermit to obtain the list of files to be sent from the
+          file whose name is given. This file must contain one file
+          specification (which may be wild) per line. If the list
+          includes files from different directories, such as a recursive
+          listing of a directory tree, the paths are recreated on the
+          server (if possible) if you include the /RECURSIVE switch;
+          otherwise all the files are sent to the current directory on
+          the server.
+
+   Now the other switches:
+
+   /AS-NAME:text
+          If a single file is being sent, send it with the given text as
+          its name. If multiple files are being sent, the text must be a
+          template that includes variables such as \v(filename),
+          \v(filenumber), \v(ntime), to allow dynamic creation of each
+          name. The same applies to the as-name field of the FTP PUT
+          command. If this switch is not included (and an as-name is not
+          included as the second filename to PUT), each file is sent with
+          its own name.
+
+   /BINARY
+   /TEXT
+   /TENEX
+          Forces this upload to take place in the given mode, regardless
+          of the current FTP TYPE setting, and without automatic
+          text/binary switching. /ASCII is a synonym for /TEXT.
+
+   /FILTER:command
+          Specifies that the file(s) is/are to be passed through the
+          given command or pipeline on their way to the server. Example:
+
+  ftp put /binary /filter:{gzip -c \v(filename)} /as-name:\v(filename).gz *
+
+   /TRANSPARENT
+   /LOCAL-CHARACTER-SET:name
+   /SERVER-CHARACTER-SET:name
+          Character-set translation for text files, explained in
+          [281]Section 3.7.
+
+   /ERROR-ACTION:{PROCEED,QUIT}
+          Overrides the prevailing [282]FTP ERROR-ACTION for the duration
+          of this PUT or MPUT command only.
+
+   /RECOVER
+          Resume an interrupted transfer where from the point of
+          interruption (explained in [283]Section 3.5.2). Synonym:
+          /RESTART.
+
+   /DELETE
+          Tells Kermit to delete each source file immediately after, and
+          only if, it has been uploaded completely and successfully.
+          This, in effect, moves the file from the client to the server.
+
+   /MOVE-TO:directory
+          Tells Kermit to move each source file to the named local
+          directory after, and only if, it has been uploaded completely
+          and successfully.
+
+   /RENAME-TO:template
+          Tells Kermit to rename each (local) source file according to
+          the given template after, and only if, it has been uploaded
+          completely and successfully. The template works as in /AS-NAME.
+
+   /SERVER-RENAME-TO:template
+          Tells Kermit to ask the server to rename each file according to
+          the given template as soon as, and only if, it has been
+          received completely and successfully. The template works as in
+          /AS-NAME. Requires write and rename access on the server, so
+          doesn't usually work with (e.g.) anonymous uploads to public
+          incoming areas where the permissions don't allow renaming.
+          Examples:
+
+        ftp mput /server-rename:\v(filename).ok *
+                Appends ".ok" to each filename on the server when it's
+                finished uploading.
+
+        ftp mput /as-name:\v(filename).tmp /server-rename:\v(filename) *
+                This is the reverse of the previous example; it uses a
+                temporary name while uploading is in progress and reverts
+                the file to its real name when uploading is complete.
+
+        ftp mput /as-name:\v(filename)
+                /server-rename:../final/\v(filename) *
+                Moves the file from the working directory to a final
+                directory when the upload is complete, but in this case
+                you have to know the pathname syntax of the server. If
+                the rename fails, the [M]PUT command fails according to
+                the [284]FTP ERROR-ACTION selection.
+
+   /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}
+          Overrides the [285]FTP FILENAMES setting for this upload only.
+
+   /PERMISSIONS:{ON,OFF}
+          Overrides the [286]FTP PERMISSIONS setting for this upload
+          only.
+
+   /UNIQUE
+          Tells Kermit to tell the server to give [287]unique names to
+          incoming files that would otherwise overwrite existing files
+          that have the same name. This switch conflicts with /UPDATE,
+          /RECOVER, /PERMISSIONS, and /SERVER-RENAME since the client has
+          no way of knowing the name assigned by the server.
+
+   /QUIET
+          Don't display file-transfer progress or statistics.
+
+   /SIMULATE
+          Shows which files would be sent without actually sending them.
+          Useful (for example) with /UPDATE (next section). The results
+          are shown in the file-transfer display (if it is not disabled)
+          and in the transaction log (if one is active). Hint: use SET
+          TRANSFER DISPLAY BRIEF.
+     _________________________________________________________________
+
+    3.5.2. Update Mode
+
+   When you include the /UPDATE switch, this means to skip sending any
+   file that already exists on the server if the local file's
+   modification date/time is not later than that of the corresponding
+   file on the server. Here is a typical application for update mode:
+   Suppose that on Computer A, you maintain a large set of files (say, a
+   collection of Web pages and graphics images, or the source files for a
+   software application), and you need to keep a parallel copy on another
+   Computer, B. Of course you could upload the entire collection every
+   day:
+
+  cd source-directory
+  ftp computerb.xyzcorp.com
+  ( authentication details... )
+  ftp cd target-directory
+  ftp put [ switches ] *
+
+   But if the total size is large or the network slow, this would be
+   unnecessarily time-consuming. Worse, if other users or sites had to
+   update whenever new files appeared in B's directory, this would cause
+   them unnecessary work. By including the /UPDATE switch:
+
+  ftp put /update [ other-switches ] *
+
+   only those files that changed since last time are uploaded. Here's how
+   it works. For each local file that is selected for uploading:
+
+     * The remote filename is determined in the normal way, according to
+       the [288]FTP FILENAMES setting, /FILENAMES switch, or the as-name,
+       if any.
+     * Kermit sends an MDTM (modification time) command for the
+       corresponding remote filename to the server.
+     * If the server does not understand the MDTM command, the file is
+       sent.
+     * If the server can't find a file with the given name, the file is
+       sent.
+     * If the local file's modification time is later than that of the
+       remote file, the file is sent.
+     * Otherwise -- the remote file exists but its modification time is
+       equal to or earlier than that of the local file -- the file is
+       skipped.
+
+   All time comparisons take place in Coordinated Universal Time
+   (UTC)([289]1), also known as GMT or Zulu time: Timezone 0; standard
+   time, without daylight savings.
+
+     WARNING: Some FTP servers, such as Novell NWFTPD.NLM, ignore or
+     misimplement the FTP specification and send local time rather than
+     UTC.
+
+   Update mode is useful only when always used in the same direction.
+   When you upload (PUT) a file with FTP, the destination file receives
+   the current timestamp on the server's computer, not the original
+   file's timestamp ([290]2). If you try to FTP PUT /UPDATE the same file
+   again, it will be skipped (as expected) since the remote copy is
+   newer. However, if you try to FTP GET /UPDATE the same file
+   ([291]Section 3.6), it will be transferred for the same reason.
+
+   To check the availability of PUT /UPDATE on a particular connection,
+   issue an FTP MODTIME command for a file that is known to exist on the
+   server. If it succeeds, PUT /UPDATE should work and in that case, you
+   can run a procedure like the one above every day: the first time, it
+   sends all the files; after that, it sends only the ones that changed.
+   If a transaction log is active, a notation is included for any files
+   that are skipped.
+
+   Notes:
+    1. Why is Coordinated Universal Time abbreviated UTC? From the
+       [292]National Institute of Standards and Technology FAQ: "In 1970
+       the Coordinated Universal Time system was devised by an
+       international advisory group of technical experts within the
+       International Telecommunication Union (ITU). The ITU felt it was
+       best to designate a single abbreviation for use in all languages
+       in order to minimize confusion. Since unanimous agreement could
+       not be achieved on using either the English word order, CUT, or
+       the French word order, TUC, the acronym UTC was chosen as a
+       compromise."
+    2. The Kermit FTP client is unusual in that, when downloading only,
+       it can set the received file's date from the file's date on the
+       server, but this should not affect the update feature. When
+       uploading to an FTP server, however, there is no mechanism for the
+       client to set the date of the uploaded file on the server.
+     _________________________________________________________________
+
+    3.5.3 Recovery
+
+   Suppose that while you are uploading a large file over a slow
+   connection, the connection is lost before the entire file is
+   transferred. With most FTP clients, you would have to start over, thus
+   resending the portion of the file that was sent already, and that is
+   already on the server. But Kermit's /RECOVER switch (Synonym:
+   /RESTART) lets you continue an interrupted transfer from the point of
+   failure, thus transferring only the part that wasn't sent already. The
+   prerequisites for recovery are:
+
+     * The transfer must be in BINARY mode, or else the client and server
+       must reside on like systems (e.g. both on some form of UNIX).
+     * The FTP server must support the SIZE command.
+
+   Here's how it works. When you include the /RECOVER switch:
+
+     * Kermit checks for conflicting switches, such as /UPDATE and
+       /UNIQUE; if /RECOVER is given with these switches an error occurs.
+       If /RECOVER is given in other circumstances where it could serve
+       no useful purpose (e.g. with arrays, pipes, or filters), it is
+       ignored.
+
+   If the switch is accepted, then for each selected file:
+
+     * If it is not binary (determined by scanning) and the client and
+       server are not on like platforms, recovery is canceled (the entire
+       file is sent). Otherwise:
+     * A SIZE command is sent for the file (using its remote name). If
+       the reply indicates the file was not found, or the SIZE command
+       was not understood, or any other kind of error, recovery is
+       canceled. Otherwise:
+     * A MDTM (modification time) command is sent for the file. If a
+       valid reply is received, and the modification time of the local
+       file is later than that of the remote file, recovery is canceled.
+       Otherwise:
+     * If the sizes of the two files are identical, the file is not sent.
+       Otherwise:
+     * Kermit seeks to the recovery spot in the local file, tells the
+       server to APPEND the data which is about to arrive to the remote
+       file, and then sends the data starting at the recovery point.
+
+   To safeguard file integrity, recovery is not attempted unless all the
+   preconditions are met. For the widest possible usefulness, APPEND is
+   used rather than RESTART. For stream transfers (the only kind that
+   Kermit supports) the results are the same.
+
+   By design, the /RECOVER switch can be included with any FTP PUT or
+   MPUT command, even if it specifies a group of files. This allows you
+   to resume an interrupted batch transfer from where it left off. The
+   files that were already completely sent are skipped, the file that was
+   interrupted is recovered, and the remaining files are uploaded.
+
+   By the way, it doesn't matter how the original partial file was
+   uploaded -- FTP, Kermit, Zmodem, etc: as long as the preconditions are
+   met, it can be recovered with FTP PUT /RECOVER, or for that matter
+   also using Kermit protocol and SEND /RECOVER.
+
+   A word of caution, however, when the original upload was in text mode
+   with character-set translation ([293]Section 3.7):
+
+     * If the original upload involved a translation from one single-byte
+       character set to another (e.g. Code Page 850 to Latin-1), recovery
+       is safe if you specify the same translations for the recovery. If
+       you don't, the resulting file will contain a mixture of character
+       sets.
+     * If the original upload involved a translation that changed the
+       size of the file (e.g. from an alphabetic Code Page or Latin
+       Alphabet to Unicode, or vice versa), recovery is NOT safe, even if
+       you specify the same translations.
+
+   Kermit has no way of knowing anything about the previous upload. As a
+   safeguard, an error occurs if you include /RECOVER and also specify a
+   character-set of UCS2 or UTF8, since recovery can't possibly work in
+   that situation. Otherwise, it's up to you to avoid unsafe recovery
+   operations.
+
+   [ [294]Top ] [ [295]FTP Top ] [ [296]C-Kermit Home ] [ [297]Kermit
+   Home ]
+     _________________________________________________________________
+
+  3.6. Downloading Files With FTP
+
+   Although uploading files with Kermit's FTP client is just as easy and
+   flexible as sending files with Kermit protocol, the same is not always
+   true for downloading because FTP servers lack some of the capabilities
+   of a Kermit server:
+
+     * If you want to get more than one file, you have to use MGET, not
+       GET, since the underlying FTP protocol is different in the two
+       cases. Kermit can't "autodetect" which one you mean, as it can
+       with PUT and MPUT, since it can't be expected to know the wildcard
+       syntax of the remote platform and/or FTP server (the same is true
+       for all other FTP clients). To complicate matters, FTP protocol
+       now includes two underlying mechanisms (NLST and MLSD) for
+       accomplishing MGET operations and, as explained in [298]Section
+       3.11, the two behave differently.
+     * Automatic text-binary mode switching is not done by the server. It
+       can be done by the client (Kermit), but in this case it is not
+       based on a file scan (since there is no way for Kermit prescan a
+       server file), but rather on the filename, using C-Kermit 7.0
+       [299]filename patterns.
+     * Some options that are available with FTP PUT can not be used with
+       FTP [M]GET or don't work the same way:
+         /PERMISSIONS (FTP protocol has no mechanism for this).
+         /[NOT-]BEFORE, /[NOT-]AFTER (because of the timezone problem).
+         /RECOVER works only in binary mode.   /RECURSIVE has limited
+       utility.
+
+   The commands for downloading are:
+
+   SET FILE DOWNLOAD-DIRECTORY [ directory ]
+          As with Kermit transfers, this command, if given, tells
+          C-Kermit where to store incoming files in the absence of a
+          specific as-name. If not given, incoming files are stored as
+          indicated by the as-name, if any, otherwise in the current
+          directory, just as with Kermit transfers. The more verbose
+          transfer display formats give the full pathname of each
+          received file, and, in case you have trouble finding a
+          downloaded file afterwards, its full path is also listed in the
+          transaction log (if you kept one), and you can also ask Kermit
+          where it went with the [300]WHERE command.
+
+   SET FTP GET-FILETYPE-SWITCHING { ON, OFF }
+          ON by default, causing Kermit to switch automatically into text
+          or binary mode for each file based on whether its name matches
+          a text pattern or binary pattern. Set this OFF, or use a /TEXT,
+          /BINARY, or /TENEX switch to defeat this feature. Use SHOW
+          PATTERNS to see the current pattern list.
+
+   [ FTP ] GET [ switches ] filename [ as-name ]
+          Asks the server to send the given file, and if it comes, stores
+          it locally under the given as-name, if any, otherwise under its
+          original name (modified according to the selected filename
+          conversion option), in your download directory, if you have
+          specified one, otherwise in the directory indicated in the
+          as-name, if any, otherwise in your current directory. If you
+          accidentally use a wildcard in the filename ("get *.txt") the
+          server will reply with a message like "File not found" (unless
+          there is a file whose name actually is "*.txt"). If FTP
+          GET-FILETYPE-SWITCHING is ON, and in the absence of any GET
+          switches to override it, the file is transferred in binary mode
+          if it matches any of Kermit's binary name patterns, and in text
+          mode if it matches any of Kermit's text name patterns, and in
+          the prevailing FTP TYPE if it matches none of these patterns.
+
+   [ FTP ] MGET [ switches ] filespec [ filespec [ filespec [ ... ] ] ]
+          Like GET, but for multiple files. One or more file
+          specifications can be given, and any or all (or none) of them
+          can contain wildcards or can be directory names. The file list
+          may not include an as-name, but you can still give one with the
+          /AS-NAME: switch.
+
+   In both the FTP GET and MGET commands, any filenames that contain
+   spaces must be enclosed in braces or doublequotes (see [301]Section 5
+   for details).
+
+   FTP downloads may be interrupted just like Kermit transfers. While the
+   transfer is in progress, type:
+
+     * X to interrupt the current file and go on to the next file.
+     * Z (or Control-C) to cancel the current file and all remaining
+       files.
+
+   Before proceeding, a brief word about temporary files. In FTP
+   protocol, the MGET command works by requesting a file list from the
+   server, and then (internally) issuing a GET command (FTP RETR protocol
+   directive) for each file. The file list returned by the server can be
+   any size at all, so in case it is huge, we don't store it in memory;
+   instead we put it in a temporary file. For troubleshooting purposes,
+   you should be aware of two points:
+
+    1. The location of the temporary file is chosen according the TMP or
+       TEMP environment variables. If neither of these variables is
+       defined, you might need to define it. In case there is not enough
+       space on the indicated disk or partition for the server's file
+       list, you might need to either clean up the temporary area, or
+       redefine the environment variable to indicate a different area
+       that has sufficient space.
+    2. If you want to look at the list yourself, use SET FTP DEBUG ON.
+       This tells Kermit to (a) give you the full pathname of the
+       temporary file at the end of each MGET command, and (b) not to
+       delete it, as it normally does.
+     _________________________________________________________________
+
+    3.6.1. FTP GET Switches
+
+   The following switches are available with FTP GET and MGET:
+
+   /TEXT
+          Specifies a text-mode transfer. Overrides the global FTP TYPE
+          setting and filename pattern-matching for the duration of the
+          current command only, All files are downloaded in text mode.
+          Synonym: /ASCII.
+
+   /BINARY
+          Specifies a binary-mode transfer. Overrides the global FTP TYPE
+          setting and filename pattern-matching for the duration of the
+          current command only. All files are downloaded in binary mode.
+
+   /TENEX
+          Like /BINARY but specifies a special binary transfer mode to be
+          used when getting 8-bit binary files from a 36-bit platform
+          such as TOPS-10, TOPS-20, or TENEX. All files are downloaded in
+          the special binary mode.
+
+   /RECOVER
+          This instructs Kermit to try to recover an incomplete download
+          from the point of failure. Works only in binary mode, and only
+          if the server supports the (not-yet-standard) FTP "REST"
+          directive. See [302]Section 3.6.3 for details. Synonym:
+          /RESTART.
+
+   /FILENAMES:{CONVERTED,LITERAL}
+          Overrides the [303]FTP FILENAMES (filename conversion) setting
+          for this download only, forcing incoming filenames to be either
+          converted or taken literally.
+
+   /AS-NAME:text
+          For GET, this is equivalent to giving an as-name after the
+          filename. For MGET, this is the only way to specify alternative
+          names for the incoming files. With MGET, the /AS-NAME text
+          should (must) contain a Kermit variable, usually \v(filename)
+          or \v(filenumber). Example:
+
+  mget /text /as-name:\v(filename).new *.c
+
+          This gets all ".c" files and stores them with "
+
+          .new" appended to their names. See the [304]C-Kermit 7.0 Update
+          Notes for details.
+
+   /COMMAND
+          This specifies that the incoming file is to be written to the
+          standard input of a command, rather than to a file. The command
+          name is the as-name from the GET command or the /AS-NAME
+          argument. If you need to refer to the incoming file's name in
+          the command, use \v(filename). See the description of the
+          regular Kermit [305]GET /COMMAND command for details and
+          examples.
+
+   /QUIET
+          Transfers the files quietly; don't put up a file-transfer
+          display.
+
+   /ERROR-ACTION:{QUIT,PROCEED}
+          This switch affects only MGET. If an error occurs with a
+          particular file, this tells whether to go on to the next file
+          (PROCEED) or to stop right away and fail (QUIT). The default is
+          PROCEED.
+
+   The file selection switches are:
+
+   /EXCEPT:{pattern} or /EXCEPT:{{pattern}{pattern}{...}}
+          Exception list for MGET; skip downloading any file whose name
+          matches any of the given patterns (when using the second
+          format, up to 64 patterns may be specified). [306]CLICK HERE
+          for syntax details.
+
+   /SMALLER-THAN:number
+          Download only files whose size is smaller than the given number
+          of bytes (octets). Requires that the FTP server support the
+          SIZE or MLSD directive.
+
+   /LARGER-THAN:number
+          Download only files whose size is greater than the given number
+          of bytes. Requires that the FTP server support the SIZE or MLSD
+          directive.
+
+   /NOBACKUPFILES
+          During MGET, don't download any files whose names end with
+          backup suffixes (.~n~ where n is a number).
+
+   /NODOTFILES
+          During MGET, don't download any files whose names begin with
+          period (.). Equivalent to /EXCEPT:{.*}.
+
+   /LISTFILE:local-filename
+          The given file contains a list of files to GET, one per line.
+          Filenames in the listfile can contain wildcard characters in
+          the syntax of the server. There is no limit on the number of
+          lines in the listfile.
+
+   /NAMELIST:local-filename
+          If this switch is given, then instead of actually retrieving
+          the selected files, the GET command retrieves a list of the
+          names of the files that would be retrieved, and places it in
+          the specifed file. The resulting file is an ordinary text file,
+          with one filename per line, suitable for reading by a person,
+          or processing by a computer program, including Kermit itself
+          (FOPEN / FREAD / FWRITE / FCLOSE), and as /FILELIST: file. If
+          the filename is omitted or given as "-" (dash, hyphen), the
+          list goes to the screen. NOTE: if you want a copy of the
+          complete list sent by the server, use SET FTP DEBUG ON, perform
+          an MGET, and the temporary file containing the list will be
+          kept rather than deleted (and Kermit tells you its name).
+
+   /UPDATE, /COLLISION:keyword
+          Explained in [307]Section 3.6.2.
+
+   /RECURSIVE
+          This means to try to download an entire directory tree, rather
+          than just files from a particular directory. In fact, FTP
+          protocol does not provide a method to request a recursive
+          download (unless the server supports MLSD; see [308]Section
+          3.11), so this works only if the FTP server does it anyway,
+          without being asked, as some do. In this case, Kermit detects
+          that names in the returned file list contain directory
+          separators, and therefore attempts to create the needed
+          directories as the files arrive. But this can work only if the
+          server is on the same kind of platform as the client, so the
+          pathname syntax can be recognized, and also because the server
+          does not switch between text and binary mode, which would be
+          vital for cross-platform transfers. Use with caution. Synonym:
+          /SUBDIRECTORIES.
+
+          Even when the server does not provide recursive file lists,
+          [M]GET /RECURSIVE forces Kermit to replicate any directory
+          structure implied or expressed by the server's file list. For
+          example:
+
+  get somepath/somefile
+
+          Gets the file named somefile from the server's somepath
+          directory and puts it Kermit's current (or download) directory,
+          whereas:
+
+  get /recursive somepath/somefile
+
+          creates the path locally and then puts the file in it.
+          Similarly for MGET:
+
+  mget */data/*
+
+          downloads all the files in all the data subdirectories of all
+          the subdirectories of the server's current directory and stores
+          them locally in Kermit's current (or download) directory,
+          whereas:
+
+  mget /recursive */data/*
+
+          re-creates the server's directory structure locally.
+
+   The FTP protocol does not include explicit mechanisms for recursion,
+   so Kermit builds upon what is available. Although an Internet draft
+   describes a mechanism ("MLSD") that would allow protocol-driven
+   recursion, similar to Kermit's File Attribute packets (circa 1984), it
+   has not yet attained RFC or standard status, and servers are not yet
+   widely available that offer this feature. In the meantime, the
+   effectiveness of MGET /RECURSIVE depends on the FTP server
+   implementation. If the server returns a recursive list in response to
+   the standard NLST command (whose behavior is ill-defined), Kermit's
+   FTP MGET /RECURSIVE command uses it to re-create the remote directory
+   tree locally. If the server supports MLSD, C-Kermit 8.0.206 and Kermit
+   95 2.1 and later are able to sense it automatically and use it, as
+   described below in [309]Section 3.11.
+
+   The /BEFORE:, /AFTER:, /NOT-BEFORE:, and /NOT-AFTER: switches are not
+   available for downloading because of the confusion with timezones.
+   Would the given times be in the local timezone, the server's timezone,
+   or GMT? The FTP server's directory listings show its own local times
+   but since we don't know what timezone the server is in, there's no way
+   to reconcile our local times with the server's. Similarly,
+   /PERMISSIONS can't be preserved in downloads because FTP protocol
+   provides no means of querying the server for a file's permission.
+
+   Source-file disposition switches:
+
+   /DELETE
+          Each file that is downloaded successfully is to be deleted from
+          the server. Requires the appropriate file access rights on the
+          server.
+
+   /SERVER-RENAME-TO:template
+          Asks the server to rename each (remote) source file immediately
+          after, and only if, it is sent correctly. See [310]PUT
+          /SERVER-RENAME-TO: for details.
+
+   Destination-file disposition switches:
+
+   /TO-SCREEN
+          Displays the incoming file on the screen rather than storing it
+          on disk. If this switch is given, the /RENAME-TO and /MOVE-TO
+          switches are ignored, the file-transfer display is suppressed,
+          and the given file(s) is/are shown on the screen. Can be used
+          with /FILTER, e.g.
+
+  get /text /to-screen /filter:more oofa.txt
+
+          In fact, you should always use /TO-SCREEN with /FILTER or
+          /COMMAND when the command would result in displaying the
+          incoming file on the screen; otherwise C-Kermit would have no
+          way of knowing to suppress its file transfer display (since it
+          can't be expected to know what the command or filter does).
+
+   /RENAME-TO:template
+          Each file that is downloaded is to be renamed as indicated if
+          and only if it was received completely and without error. The
+          template can be literal text or can contain variables that are
+          evaluated for each file. For MGET, the text must contain
+          variables; for GET it can be a literal string. The \v(filename)
+          variable contains the name of the current file, so:
+
+  ftp mget /rename-to:\v(filename).ok *
+
+          causes each file that is successfully downloaded to have ".ok"
+          appended to its name. For details see [311]Section 4.1 of the
+          [312]C-Kermit 7.0 Update Notes.
+
+   /MOVE-TO:text
+          Just like /RENAME-TO:, except the text denotes the name of a
+          directory to which successfully downloaded files are to be
+          moved. If the directory does not exist, it is created.
+
+   The file transfer display does not show the /MOVE-TO or /RENAME-TO
+   value, since the incoming file has not yet been moved or renamed.
+     _________________________________________________________________
+
+    3.6.2. Filename Collisions
+
+   What should happen if an incoming file has the same name as an
+   existing file in the same directory? By default, Kermit's FILE
+   COLLISION setting applies: BACKUP, RENAME, UPDATE, DISCARD, etc, as
+   described in [313]Using C-Kermit. Kermit's default FILE COLLISION
+   setting is BACKUP (rename the existing file and store the incoming
+   file under its own name) and therefore this is also the default FTP
+   collision action.
+
+   The name under which an incoming file is to be stored is determined as
+   follows:
+
+     * If an as-name was given, the as-name is used. Otherwise:
+     * If the client and server platforms are alike or [314]FTP FILENAMES
+       is set to LITERAL (or the /FILENAMES:LITERAL switch was given for
+       this download), the incoming filename is used literally.
+       Otherwise:
+     * The incoming filename is converted to a form that is friendly to
+       the local platform. For UNIX, for example, incoming filenames that
+       are all uppercase (as they might be from, say, VMS or an IBM
+       mainframe) are converted to lowercase.
+
+   If the resulting name coincides with the name of a local file that
+   already exists, we have a filename collision. Collisions are handled
+   according to the currently selected collision action:
+
+   SET FTP COLLISION { BACKUP, RENAME, UPDATE, DISCARD, APPEND, OVERWRITE
+          }
+          This establishes a filename collision for FTP, separate from
+          the Kermit one. The initial FTP collision setting is inherited
+          from Kermit's FILE COLLISION setting when the first FTP command
+          is given, but subsequent changes to Kermit's FILE COLLISION
+          setting do not affect the FTP COLLISION setting. SHOW FTP tells
+          the current FTP COLLISION setting.
+
+   FTP GET /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}
+          Overrides the current FTP COLLISION action for this download
+          only.
+
+   FTP GET /UPDATE
+          This is equivalent to GET /COLLISION:UPDATE, and is included
+          for symmetry with PUT /UPDATE
+
+   FTP GET /UPDATE and /COLLISION:UPDATE mean to download only those
+   files whose modification dates on the server are later than those on
+   the client. Date-time comparisons are done in Coordinated Universal
+   Time (UTC, GMT, ZULU). The command:
+
+     FTP MGET /COLLISION:APPEND /AS-NAME:newfilename *.*
+
+   Downloads all matching remote files into a single local file (in
+   whatever order the server sends them).
+     _________________________________________________________________
+
+    3.6.3. Recovery
+
+   Recovery is available for downloads too, but there are some
+   differences from the uploading case described in [315]Section 3.5.3:
+
+     * The transfer must be in BINARY mode. It can not be in text mode,
+       even if the FTP server is on the same kind of platform as Kermit,
+       and even if there is no character-set translation. The original
+       download must also have been in binary mode.
+     * The FTP server must support the REST ("restart") directive.
+       Unfortunately, this is not a standard command; at this writing, it
+       is described only in an Internet Draft, not an RFC or Internet
+       Standard, but nevertheless it is found in several popular FTP
+       servers, such as [316]ProFTPD.
+
+   Here's how download recovery works:
+
+     * Kermit checks for conflicting switches, such as /UPDATE, /COMMAND,
+       or /FILTER. If /RECOVER is given with these switches an error
+       occurs.
+     * The prevailing transfer mode (SET FTP TYPE) must be BINARY. If it
+       is not, the /BINARY switch must have been included with the FTP
+       [M]GET command.
+
+   If the /RECOVER switch is accepted, then for each selected file:
+
+     * A SIZE command is sent for the file (using its remote name). If
+       the reply indicates the file was not found, or the SIZE command
+       was not understood, or any other kind of error, recovery is
+       canceled (i.e. the entire file is downloaded).
+     * If the sizes of the two files are identical, the file is not sent.
+       Otherwise:
+     * Kermit sends the REST directive to the server, indicating the size
+       of the local file. If the server responds affirmatively, Kermit
+       opens the local file in append mode and appends the incoming data
+       to it. Otherwise, recovery is canceled and the entire file is
+       downloaded.
+
+   The /RECOVER switch can be included with any FTP GET or MGET command,
+   even if it specifies a group of files. This lets you resume an
+   interrupted batch transfer from where it left off. The files that were
+   already completely sent are skipped, the file that was interrupted is
+   recovered, and the remaining files are uploaded. BUT... unlike with
+   uploading, where this can be done with any mixture of text and binary
+   files, when downloading, it can only be done if all the files are
+   binary.
+
+   It doesn't matter how the original partial file was downloaded -- FTP,
+   Kermit, HTTP, Zmodem, etc: as long as the preconditions are met, it
+   can be recovered with FTP [M]GET /RECOVER, or for that matter also
+   with GET /RECOVER (using Kermit protocol).
+
+   [ [317]Top ] [ [318]FTP Top ] [ [319]C-Kermit Home ] [ [320]Kermit
+   Home ]
+     _________________________________________________________________
+
+  3.7. Translating Character Sets
+
+   A possibly unique feature of Kermit's FTP client is its ability to
+   convert character sets when transferring files in text mode,
+   independent of the capabilites of the FTP server, as well as to
+   translate the character sets of filenames regardless of transfer mode.
+   For compatibility with existing FTP clients, and because there is a
+   certain performance penalty, Kermit won't do this unless you ask for
+   it. If you enable this feature, you need to inform Kermit of the
+   character set (to be) used on the server and in some cases (explained
+   below) also the local file character set. This discussion assumes you
+   know a bit about character sets (as you must if you have to use them);
+   see Chapter 16 of [321]Using C-Kermit for a detailed treatment. The
+   Kermit commands for FTP character-set conversion are:
+
+   SET FTP CHARACTER-SET-TRANSLATION { ON, OFF }
+          Whether to translate character sets when transferring text
+          files with FTP. OFF by default. Set this to ON to enable
+          character-set translation for subsequent FTP uploads and
+          downloads.
+
+   SET FTP SERVER-CHARACTER-SET [322]name
+          Text character set (to be) used by the server. Most FTP servers
+          are ignorant of character sets, so all translations are done
+          unilaterally by Kermit's FTP client. This means that when
+          downloading files, you must know in advance the character-set
+          used in the files you are downloading (and in their names).
+          When uploading, you must specify the character-set to which
+          local filenames and text-file contents are to be translated for
+          transmission to the server. If you SET FTP
+          CHARACTER-SET-TRANSLATION ON but do not specify an FTP
+          SERVER-CHARACTER-SET, [323]UTF8 is used, since this is the new
+          Internet standard international character set; it is upwards
+          compatible with ASCII and it encompasses most written languages
+          and therefore does not favor any particular group of people, as
+          any other default would do. If you SET FTP SERVER-CHARACTER-SET
+          to something (anything) when FTP CHARACTER-SET TRANSLATION is
+          OFF, this also sets the latter ON.
+
+   SET FILE CHARACTER-SET [324]name
+          This is the regular Kermit (non-FTP-specific) command for
+          identifying the character set (to be) used in local text files
+          and filenames.
+
+   TO REITERATE: If you SET FTP CHARACTER-SET TRANSLATION ON but do not
+   specify an FTP SERVER-CHARACTER-SET, outbound text files are converted
+   to UTF-8 and inbound text files are assumed to be UTF-8. If this is
+   not appropriate, be sure to also specify the desired FTP
+   SERVER-CHARACTER-SET.
+
+   You can use "special" (non-ASCII) characters in filenames in all the
+   client / server file management commands (FTP MKDIR, RMDIR, DIRECTORY,
+   VDIRECTORY, DELETE, etc), and also in file-transfer commands. When
+   giving commands such as FTP DIR (RDIR) and FTP PWD (RPWD), the reply
+   is translated too, so you can read it. In this example, the client and
+   server use entirely different codes to represent the special
+   characters of German:
+
+  C-Kermit> ftp xyzcorp.de /anonymous
+  C-Kermit> set ftp server-character-set latin1
+  C-Kermit> set file character-set german
+  C-Kermit> rcd Städte
+  C-Kermit> rpwd
+  "/pub/ftp/Städte is current directory"
+  C-Kermit> rdir
+  -rw-rw----  1 olaf     54018 Jan  6 17:58 Adenbüttel.txt
+  -rw-rw----  1 ursula     373 Jan  5 15:19 Aßlar.txt
+  -rw-rw----  1 gisbert    482 Jan  5 15:20 Blowatz.txt
+  -rw-rw----  1 gudrun     124 Jan  5 15:19 Böblingen.txt
+  -rw-rw----  1 olga     14348 Jan  7 14:23 Köln.txt
+
+   When the client and server file systems use different character sets,
+   you should take care to use only those characters that the two sets
+   share in common when creating filenames or text-file contents. For
+   example, PC code pages contain a lot line- and box-drawing characters,
+   and sometimes "smart quotes", etc, that are not found in ISO standard
+   8-bit character sets. You should be especially careful to avoid using
+   such characters in filenames.
+
+   [ [325]C-Kermit Character Sets ]
+     _________________________________________________________________
+
+    3.7.1. Character Sets and Uploading
+
+   Kermit's PUT and MPUT commands include full file-scanning
+   capabilities, as described in [326]Section 4. Thus if FTP
+   CHARACTER-SET-TRANSLATION is ON and your character-set associations
+   are set up appropriately, Kermit automatically switches on a per-file
+   basis between text and binary mode, and for each text file between
+   your chosen 7-bit text character set (e.g. ASCII or ISO 646 German),
+   8-bit text (e.g. Latin-1 or Japanese EUC), UCS-2, and UTF-8, and
+   converts each of these automatically to the server character-set, and
+   furthermore automatically differentiates between the Little and Big
+   Endian forms of UCS-2, always sending in Big Endian form.
+
+     WARNING: It is not advisable to use UCS-2 (or any Unicode
+     transformation other than UTF-8) "on the wire", i.e. as a server
+     character set. Most FTP servers are not able to cope with it, since
+     it contains lots of 0 (NUL) characters. If you do use it, Kermit
+     does not translate filenames to or from UCS-2, for reasons well
+     known to C programmers (for example, UNIX APIs assume filename
+     strings are NUL-terminated). [327]UTF-8 is the preferred (and
+     standard) Unicode format for the Internet.
+
+   FTP character-set translations differ from the regular Kermit ones by
+   not restricting translations to a file-character-set /
+   transfer-character-set pair. You can have Kermit's FTP client
+   translate between any pair of character sets it knows about. You can
+   see the list of supported character sets by typing either of the
+   following:
+
+  set ftp server-character-set ?
+  set file character-set ?
+
+   A typical list looks like this ([328]CLICK HERE for an explanation of
+   the names):
+
+  C-Kermit>set file char ? One of the following:
+   ascii            cp869-greek       hebrew-7         mazovia-pc
+   british          cyrillic-iso      hebrew-iso       next-multinational
+   bulgaria-pc      danish            hp-roman8        norwegian
+   canadian-french  dec-kanji         hungarian        portuguese
+   cp1250           dec-multinational iso2022jp-kanji  shift-jis-kanji
+   cp1251-cyrillic  dg-international  italian          short-koi
+   cp1252           dutch             jis7-kanji       spanish
+   cp437            elot927-greek     koi8             swedish
+   cp850            elot928-greek     koi8r            swiss
+   cp852            euc-jp            koi8u            ucs2
+   cp855-cyrillic   finnish           latin1-iso       utf8
+   cp858            french            latin2-iso
+   cp862-hebrew     german            latin9-iso
+   cp866-cyrillic   greek-iso         macintosh-latin
+  C-Kermit>
+
+   Thus you can translate not only between private sets (like PC code
+   pages) and standard ones (like Latin-1) as in Kermit protocol, but
+   also between any given pair of private sets (e.g. CP852 and Mazovia).
+   All conversions go through Unicode as the intermediate character set,
+   resulting in a minimum of character loss, since Unicode is a superset
+   of all other character sets known to Kermit.
+
+   In addition to the SET commands listed above, the FTP PUT and MPUT
+   commands include switches that apply only to the current command:
+
+   /LOCAL-CHARACTER-SET:name
+   /SERVER-CHARACTER-SET:name
+          Use these switches to force a particular translation. These
+          switches override the global FTP CHARACTER-SET-TRANSLATION and
+          SERVER-CHARACTER-SET settings and also character-set
+          differentiation by file scanning for the duration of the PUT or
+          MPUT command. The file scan is still performed, however, to
+          determine whether the file is text or binary; thus these
+          switches do not affect binary files unless you also include the
+          /TEXT switch to force all files to be treated as text.
+
+   In other words, if you include one or both of these switches with a
+   PUT or MPUT command, they are used. Similarly, the /TRANSPARENT switch
+   disables character-set translation for the PUT or MPUT command despite
+   the prevailing FTP CHARACTER-SET-TRANSLATION and SERVER-CHARACTER-SET
+   settings.
+
+   When uploading, the FILE CHARACTER-SET setting is ignored unless you
+   have forced Kermit not to [329]scan local files by including a /TEXT
+   or /BINARY switch with your [M]PUT command, or by disabling automatic
+   text/binary switching in some other way.
+
+   Examples:
+
+    1. Suppose you have a CP852 (East European) text file that you want
+       to upload and store in ISO Latin Alphabet 2 encoding:
+  ftp put /local-char:cp852 /server-char:latin2 magyar.txt
+    2. Suppose you always want your text files converted to Latin-2 when
+       uploading with FTP. Then put:
+  set ftp server-character-set latin2
+       in your Kermit customization file, and then you can omit the
+       /SERVER-CHARACTER-SET: switch from your FTP PUT commands:
+  ftp put /local-char:cp852 magyar.txt
+    3. Now suppose that all the text files on your PC are written in
+       Hungarian, but they have a variety of encodings, and you don't
+       want to have to include the /LOCAL-CHARACTER-SET: switch on every
+       FTP PUT command, or (more to the point) you want to be able to
+       send a mixture of these files all at once. Put these commands in
+       your Kermit customization file:
+  set ftp server-character-set latin2            ; ISO 8859-2
+  set file default 7-bit-character-set hungarian ; ISO 646 Hungarian
+  set file default 8-bit-character-set cp852     ; PC East European Code Page
+       and now PUT and MPUT will automatically detect and switch among
+       ISO 646 Hungarian, Code Page 852, UTF-8, and UCS-2 encodings,
+       translating each one to Latin-2 for uploading:
+  ftp put *.txt
+
+   And since binary files are also detected automatically, the latter can
+   be simplified to:
+
+  ftp put *
+
+   even when "*" matches a diverse collection of binary and text files,
+   because translations are skipped automatically for binary files.
+     _________________________________________________________________
+
+    3.7.2. Character Sets and Downloading
+
+   The commands and switches are the same as for uploading, but automatic
+   character-set switching works differently, since Kermit can't scan the
+   server files in advance. Instead, the transfer mode (text or binary)
+   is based on the filenames; each name is compared with Kermit's list of
+   text name patterns and binary name patterns. If the name matches a
+   binary pattern (for example, if the filename is oofa.tar.gz and one of
+   the filename patterns is "*.gz"), the file is downloaded in binary
+   mode; otherwise if it matches a text pattern (e.g. oofa.txt matches
+   "*.txt"), it is transferred in text ("ascii") mode. Otherwise, it is
+   transferred in the prevailing FTP TYPE.
+
+   In C-Kermit 8.0, the pattern lists used with FTP GET are not the same
+   lists used with Kermit transfers, and can not be viewed with SHOW
+   PATTERNS, nor adjusted with ADD and REMOVE TEXT-PATTERNS and
+   BINARY-PATTERNS, or SET FILE TEXT-PATTERNS and BINARY-PATTERNS.
+   Configuration of the FTP patterns list will be added in a future
+   release.
+
+   Examples:
+
+   get /server-char:latin1 /local-char:cp850 Grüße.txt
+          In this command, the filename contains special characters,
+          which you enter using whatever character set your local
+          computer uses, in this case PC Code Page 850 (cp850). The
+          command tells Kermit (in case it didn't know already from its
+          FILE CHARACTER-SET setting) that the local character set is
+          cp850 and the server's character-set is ISO 8859-1 Latin
+          Alphabet 1 (latin1). Kermit translates the filename from cp850
+          to latin1 and sends the latin1 name to the server. Since it's a
+          text file (matches "*.txt"), its contents are translated to
+          cp850 on arrival, and it is saved with a cp850 name.
+
+   mget /text /server:latin1 /local:utf8 *.txt
+          This command:
+
+          + Tells C-Kermit that the server's files are encoded in ISO
+            8859-1 Latin Alphabet 1.
+          + Tells C-Kermit to translate the incoming files into Unicode
+            UTF-8 for storage.
+          + Asks the server to send all ".txt" files in text mode.
+
+   mget /server:latin1 /local:utf8 *
+          Tells Kermit to get all files from the server's directory,
+          switching between text and binary mode based on the filename.
+          The names of all the files are translated (to UTF-8 in this
+          case), but contents are translated (also to UTF-8) only for
+          text files.
+
+   Note that any pair of 8-bit character sets is likely to have some
+   incompatibilities. Any characters in the source file that do not have
+   equivalents in the destination file's character set are converted to
+   question marks. This applies to both filenames and to text file
+   contents.
+
+   Also note that the server's ability to accept special characters in
+   filenames depends on the particular server. For example:
+
+  get Grüße.txt
+
+   works with WU-FTPD, but:
+
+  mget Grüß*.txt
+
+   does not.
+     _________________________________________________________________
+
+    3.7.3. RFC2640
+
+   [330]RFC2640, July 1999, specifies a method by which the FTP client
+   and server can negotiate the use of UTF8. However, RFC2640-capable
+   servers are rare to nonexistent at this writing, and in any case you
+   don't need them to be able to transfer text in UTF8. C-Kermit lets you
+   upload and download text files in any character set it knows about,
+   converting to or from any other character set it knows about, without
+   the knowledge, permission, or cooperation of the server, and
+   regardless of its capabilities.
+
+   [ [331]Top ] [ [332]FTP Top ] [ [333]C-Kermit Home ] [ [334]Kermit
+   Home ]
+     _________________________________________________________________
+
+  3.8. FTP Command Shortcuts
+
+   C-Kermit's FTP client coexists with other C-Kermit functions by
+   requiring the "ftp" prefix for each FTP-related command: FTP OPEN, FTP
+   GET, FTP BYE, and so on. For interactive use, however, this can be
+   rather awkward and sometimes surprising, for example when a GET
+   command starts a Kermit GET rather than an FTP GET. In fact, many
+   Kermit commands might just as easily apply to an FTP connection: GET,
+   PUT (SEND), BYE, and CLOSE. The following command lets you choose how
+   these commands are interpreted:
+
+   SET GET-PUT-REMOTE { AUTO, KERMIT, FTP }
+          Controls the orientation of GET, PUT, REMOTE and other
+          file-transfer and client/server commands that might apply to
+          either Kermit or FTP. The default setting is AUTO, meaning that
+          these commands apply to FTP if an FTP connection is open, and
+          to Kermit otherwise. KERMIT means they always apply to Kermit,
+          FTP means they always apply to FTP.
+
+   Here is a complete list of affected commands:
+
+ Kermit Command               FTP Equivalent
+  (none)                       FTP [ OPEN ]
+  LOGIN                        FTP USER
+  LOGOUT                       FTP RESET
+  BYE                          FTP BYE
+  FINISH                       FTP BYE
+  CLOSE                        FTP BYE
+  HANGUP                       FTP BYE
+  BINARY                       FTP TYPE BINARY
+  TEXT (or ASCII)              FTP TYPE ASCII
+  SEND (or PUT)                FTP PUT
+  MSEND (or MPUT)              FTP MPUT
+  RESEND                       FTP PUT /RECOVER
+  CSEND                        FTP PUT /COMMAND
+  GET                          FTP GET
+  MGET                         FTP MGET
+  REGET                        FTP GET /RECOVER
+  REMOTE HELP      (RHELP)     FTP HELP
+  REMOTE CD        (RCD)       FTP CD (CWD)
+  REMOTE PWD       (RPWD)      FTP PWD
+  REMOTE DIRECTORY (RDIR)      FTP DIRECTORY
+  REMOTE DELETE    (RDEL)      FTP DELETE
+  REMOTE MKDIR     (RMKDIR)    FTP MKDIR
+  REMOTE RMDIR     (RRMDIR)    FTP RMDIR
+  REMOTE RENAME    (RRENAME)   FTP RENAME
+  REMOTE TYPE      (RTYPE)     FTP TYPE
+  REMOTE EXIT      (REXIT)     FTP BYE
+
+   The commands in the right-hand column always access FTP. The commands
+   in the left column can access either Kermit protocol or FTP:
+
+     * When GET-PUT-REMOTE is set to KERMIT, or to AUTO when there is no
+       FTP connection, the commands in the left-hand column access Kermit
+       protocol, and those right-hand column are required for FTP.
+     * When GET-PUT-REMOTE is set to FTP, or to AUTO when there is an
+       active FTP connection, the commands in the left-hand column access
+       the FTP connection and can not be used to access Kermit protocol.
+       In this case, if you want to be able to use both Kermit protocol
+       and the FTP connection, you must SET GET-PUT-REMOTE KERMIT, and
+       then use the FTP commands in the right-hand column to access the
+       FTP connection.
+
+   Note that file-management commands such as DIRECTORY, DELETE, CD, PWD,
+   MKDIR, RMDIR, HELP, RENAME, COPY, TYPE, and so on, always apply
+   locally, no matter what kind of connection you have. This is the
+   opposite of most FTP clients, where these commands are intended for
+   the server, and require an "L" prefix for local execution (e.g. "dir"
+   gets a directory listing from the server, "ldir" gets a local
+   directory listing). To illustrate with the CD command and a typical
+   UNIX FTP client:
+
+ Client   Server      Change Local Directory     Change Remote Directory
+  FTP      FTP         lcd                        cd (cwd)
+  Kermit   Kermit      cd                         rcd, remote cd
+  Kermit   FTP         cd                         ftp cd, rcd, remote cd
+
+   Also note that not all REMOTE commands are useful with FTP, since FTP
+   servers do not offer the corresponding functions. These include:
+
+     * REMOTE ASSIGN  - FTP servers don't have variables
+     * REMOTE COPY    - FTP servers don't copy files
+     * REMOTE HOST    - FTP servers don't execute host (shell) commands
+     * REMOTE KERMIT  - FTP servers don't execute Kermit commands
+     * REMOTE PRINT   - FTP servers don't print files
+     * REMOTE QUERY   - FTP servers don't have variables
+     * REMOTE SET     - FTP servers don't have Kermit settings
+     * REMOTE WHO     - FTP servers don't send user lists
+
+   Finally note that command shortcuts do not apply to the HELP command.
+   For help about an FTP command, use (for example) "help ftp delete",
+   not "help delete" or "help rdelete".
+
+   [ [335]Top ] [ [336]FTP Top ] [ [337]C-Kermit Home ] [ [338]Kermit
+   Home ]
+     _________________________________________________________________
+
+  3.9. Dual Sessions
+
+   You can have an FTP session open at the same time as a regular Kermit
+   SET LINE or SET HOST (terminal) session. In this case, the default SET
+   GET-PUT-REMOTE AUTO setting should ensure that all "two-faced"
+   commands like GET, PUT, REMOTE, HANGUP, BYE, etc, apply to the Kermit
+   session, and all commands for the FTP session must include the FTP
+   prefix. To be absolutely certain, you can use SET GET-PUT-REMOTE
+   KERMIT.
+
+  ftp foo.bar.baz.com
+  if fail ...
+  (log in)
+  set host foo.bar.baz.com
+  if fail ...
+  (log in)
+
+   Now you have both an FTP and Telnet connection to the same host (of
+   course they could also be to different hosts, and you could also have
+   a direct or dialed serial connection instead of a Telnet connection).
+   Now assuming you have a Kermit server on the far end of the Kermit
+   connection:
+
+  rcd incoming      ; Changes Kermit server's directory (= REMOTE CD)
+  ftp cd incoming   ; Changes FTP server's directory
+  put oofa.txt      ; Sends a file on the Kermit connection
+  ftp put oofa.txt  ; Sends a file on the FTP connection
+  bye               ; Shuts down the Kermit connection
+  ftp bye           ; Shuts down the FTP connection
+
+   Note that PUT and SEND are synonyms for both FTP and Kermit
+   connections.
+
+   You can also establish dual sessions on the Kermit command line:
+
+  kermit -j host1 -9 host2
+
+   This makes a Telnet connection to host1 and an FTP connection to
+   host2.
+
+   [ [339]Top ] [ [340]FTP Top ] [ [341]C-Kermit Home ] [ [342]Kermit
+   Home ]
+     _________________________________________________________________
+
+  3.10. Automating FTP Sessions
+
+   Most of Kermit's scripting features can be used to make and control
+   FTP sessions: FOR and WHILE loops, IF-ELSE and SWITCH constructions,
+   variables, arrays, built-in functions, and all the rest. You can't use
+   INPUT, MINPUT, OUTPUT, CLEAR, or SCRIPT on an FTP session, but these
+   are not needed since the FTP protocol is well defined.
+
+   [343]CLICK HERE for an FTP scripting tutorial.
+
+    3.10.1. FTP-Specific Variables and Functions
+
+   The following variable tells whether an FTP connection is open:
+
+   \v(ftp_connected)
+          1 if there is an active FTP connection, 0 if there isn't.
+
+   The FTP OPEN command sets:
+
+   \v(ftp_host)
+          The host to which the most recent FTP connection was made.
+
+   \v(ftp_security)
+          The security method negotiated for the current FTP session. The
+          value is "NULL" when no security is used. See [344]3.2. Making
+          Secure FTP Connections.
+
+   \v(ftp_server)
+          The OS type (UNIX, VMS, etc) of the FTP server host.
+
+   The FTP USER command (or FTP OPEN /USER:, or FTP with automatic login)
+   sets:
+
+   \v(ftp_loggedin)
+          1 if you are logged in to an FTP server, 0 if you are not.
+
+   The current COMMAND-PROTECTION-LEVEL and DATA-PROTECTION-LEVEL values
+   are reflected in:
+
+   \v(ftp_cpl)
+   \v(ftp_dpl)
+          The values are "clear", "confidential", "safe" or "private".
+          See [345]3.2. Making Secure FTP Connections.
+
+   The FTP GET-PUT-REMOTE setting is reflected in:
+
+   \v(ftp_getputremote)
+          The values are "auto", "ftp", or "kermit".
+
+   Every FTP command sets the \v(success) variable, as well as the
+   following two FTP-specific variables:
+
+   \v(ftp_code)
+          The standardized numeric FTP protocol code from the server's
+          response to the last client command, a 3-digit decimal number
+          defined in [346]RFC959. Briefly:
+
+          1xx = Positive Preliminary Reply
+          2xx = Positive Completion Reply
+          3xx = Positive Intermediate Reply
+          4xx = Transient Negative Completion Reply
+          5xx = Permanent Negative Completion Reply
+
+   \v(ftp_message)
+          The text message, if any, from the server's response to the
+          last client command. If the most recent response had multiple
+          lines, this variable has only the final line. These messages
+          are not standardized and vary in format and content from server
+          to server. Synonym: \v(ftp_msg).
+
+   FTP file transfers set the regular Kermit transfer status variables:
+
+  \v(cps)         Characters per second of most recent transfer.
+  \v(filespec)    File specification used in most recent transfer.
+  \v(fsize)       Size of file most recently transferred.
+  \v(tfsize)      Total size of file group most recently transferred.
+  \v(xferstatus)  Status of most recent transfer (0 = success, 1 = failure).
+  \v(tftime)      Elapsed time of most recent transfer, in seconds.
+
+   During an FTP transfer, the per-file variables are:
+
+  \v(filename)    Name of current file.
+  \v(filenumber)  Ordinal file number in group (1, 2, 3, ...)
+     _________________________________________________________________
+
+    3.10.2. Examples
+
+   Let's begin with a simple example showing how to log in, send some
+   files, and log out:
+
+  define error if fail { ftp bye, stop 1 Error: \%1 }
+  set transact brief
+  log t
+  ftp ftp.xyzcorp.com /anonymous
+  if fail stop 1 Connection failed
+  if not \v(ftp_loggedin) stop 1 Login failed
+  ftp cd incoming
+  error {ftp cd}
+  cd upload
+  error {local cd}
+  ftp put /delete *
+  error {put}
+  ftp bye
+
+   First we define an error handling macro to be used after the
+   connection is made. Then we set up a brief-format transaction log to
+   keep a record of our file transfers. Then we make a connection to the
+   host and log in anonymously. The "if fail" command checks whether the
+   connection was made. The "if not" command checks whether login was
+   successful. Obviously the script should not continue unless both tests
+   succeed.
+
+   Next we change to the server's 'incoming' directory and to our own
+   'upload' directory, and send all the files that are in it (they can be
+   any mixture of text and binary files), deleting each source file
+   automatically after it is successfully uploaded. Each of these
+   operations is checked with the ERROR macro, which prevents the script
+   from continuing past a failure.
+
+   Finally we close the FTP session with the "bye" command.
+
+   Just like any other Kermit script, this one can be used in many ways:
+
+     * It can be stored in a file, and Kermit can be told to TAKE the
+       file.
+     * In UNIX, it can be a "[347]kerbang" script and therefore run
+       directly from the shell prompt or as a cron job.
+
+   We could have used command shortcuts like "rcd", "put", and "bye", but
+   since they can be ambiguous under certain circumstances, it is better
+   to avoid them in scripts; they are intended mainly for convenience
+   during interactive use. However, if you wish to use the shortcuts in a
+   script, you can do it this way (error handling omitted for brevity):
+
+  local \%t                       ; Declare a local temporary veriable
+  assign \%t \v(ftp_getputremote) ; Save current FTP GET-PUT-REMOTE setting
+  set ftp get-put-remote ftp      ; Choose FTP orientation
+  ftp xyzcorp.com /anonymous      ; Open an FTP connection
+  get oofa.txt                    ; GET a file
+  put foo.bar                     ; PUT a file
+  rdel yesterday.log              ; Delete a file on the server
+  bye                             ; Log out and disconnect from server.
+  set ftp get-put-remote \%t      ; Restore previous GET-PUT-REMOTE setting
+
+   Of course, FTP scripts can also be written as macros. This lets you
+   pass parameters such as hostnames, usernames, and filenames to them:
+
+  define doftpget {
+      if < \v(argc) 4 end 1 Usage: \%0 host user remotefile [ localfile ]
+      ftp \%1 /user:\%2
+      if fail end 1 FTP OPEN \%1 failed
+      if not \v(ftp_loggedin) end 1 FTP LOGIN failed
+      ftp get {\%3} {\%4}
+      if fail end 1 FTP GET \%3 failed
+      ftp bye
+  }
+
+   Add this definition to your Kermit customization file, and it will
+   always be available when you start Kermit. This macro lets you
+   download a file with FTP by giving a single command, e.g.:
+
+  doftpget xyzcorp.com anonymous oofa.txt
+     _________________________________________________________________
+
+    3.10.3. Automating Secure FTP Sessions
+
+   Often when making secure connections, you are prompted interactively
+   for certain information or permission to proceed. These prompts can
+   stop an automated procedure. To avoid them, you must give the
+   appropriate commands to disable them, and/or supply the prompted-for
+   information beforehand. Here are a few hints:
+
+     * Make sure that SET TAKE ERROR and SET MACRO ERROR are both OFF.
+       This is the default, but in case you have set either one of these
+       ON in your script or initialization file, this makes the script
+       halt on any kind of error. Normally you would want to check each
+       operation for success or failure and take appropriate action.
+     * On SSL and TLS connections, you may be asked whether it is OK to
+       proceed with a connection to server that presents a self-signed
+       certificate. You can use the SET AUTHENTICATION SSL (or TLS)
+       VERIFY or SET AUTH SSL (or TLS) CERTS-OK commands to avoid this
+       prompt by not requesting a certificate from the peer.
+     * (More to be added...)
+
+   [ [348]Top ] [ [349]FTP Top ] [ [350]FTP Script Tutorial ] [
+   [351]C-Kermit Home ] [ [352]Kermit Home ]
+     _________________________________________________________________
+
+  3.11. Advanced FTP Protocol Features
+
+   The remainder of the FTP documention (through the end of Section 3) is
+   new to C-Kermit 8.0.206, but we leave it in black to prevent
+   headaches. Except for titles.
+     * [353]TERMINOLOGY
+     * [354]FEATURE NEGOTIATION
+     * [355]USING MGET: NLST VERSUS MLSD
+     * [356]EXAMPLES
+     * [357]REFERENCES
+
+   The new releases of [358]C-Kermit (8.0.206) and [359]Kermit 95 (2.1)
+   support new FTP protocol features from RFC 2389 as well as most of
+   what's in the Elz and Hethmon Extensions to FTP Internet Draft (see
+   [360]References). Some of these features, such as SIZE (request a
+   file's size), MDTM (request file's modification time), and REST
+   (restart interrupted transfer) have been widely implemented in FTP
+   clients and servers for years (as well as in the initial release of
+   the Kermit FTP clients). Others such as FEAT and MLSD are rarely seen
+   and are new to the upcoming Kermit releases. TVFS (Trivial Virtual
+   File Store) is supported implicitly, and the UTF-8 character-set is
+   already fully supported at the protocol and data-interchange level.
+
+   For Kermit users, the main benefit of the new FTP protocol extensions
+   is the ability to do recursive downloads. But the extensions also
+   introduce complications and tradeoffs that you should be aware of. Of
+   course Kermit tries to "do the right thing" automatically in every
+   case for backwards compatibility. But (as noted later) some cases are
+   inherently ambiguous and/or can result in nasty surprises, and for
+   those situations new commands and switches are available to give you
+   precise control over Kermit's behavior, in case the defaults don't
+   produce the desired results.
+     _________________________________________________________________
+
+   3.11.1. Terminology Command-line FTP clients such as Kermit (as well
+   as the traditional FTP programs found on Unix, VMS, ..., even Windows)
+   have commands like PUT, MPUT, GET, MGET, and BYE, which they convert
+   into zero or more FTP protocol commands, such as NLST, RETR, QUIT. For
+   clarity, we'll use "command" to refer to commands given by the user to
+   the FTP client, and "directive" for FTP protocol commands sent by the
+   FTP client to the FTP server.
+     _________________________________________________________________
+
+   3.11.2. Feature Negotiation New FTP protocol features are negotiated
+   by the client sending a FEAT directive and the server responding with
+   a list of (new) features it supports, or else with an error indication
+   if it does not support the FEAT directive at all, in which case the
+   client has to guess which new features it supports (Kermit guesses
+   that it supports SIZE and MDTM but not MLST). Note that the MLST
+   feature includes MLSD, which is not listed separately as a feature.
+
+   Guessing is nice when it works, but sometimes it doesn't, and some FTP
+   servers become confused when you send them a directive they don't
+   understand, or they do something you didn't want, sometimes to the
+   point of closing the connection. For this reason, Kermit lets you
+   override default or negotiated features with the following new
+   commands:
+
+   FTP { ENABLE, DISABLE } FEAT
+          Enables or disables the automatic sending of a FEAT directive
+          upon connection to an FTP server. Note that
+          FTP [ OPEN ] /NOINIT   also inhibits sending the FEAT directive
+          (and several others) for the connection being OPEN'd, but
+          without necessarily disabling FEAT for subsequent connections
+          in the same Kermit instance. FEAT is ENABLED by default, in
+          which case many FTP servers are likely to reply:
+
+500 'FEAT': command not understood
+
+          which is normally harmless (but you never know). (In C-Kermit
+          8.0.208, this error message is suppressed unless you SET FTP
+          DEBUG ON.)
+
+   FTP ENABLE { MDTM, MLST, SIZE }
+          Enables the given directive for implicit use by the FTP GET and
+          MGET commands in case it has been disabled or erroneously
+          omitted by the server in its FEAT response. Note: MLSD can be
+          used in the FTP ENABLE and DISABLE commands as a synonym for
+          MLST. YOU MUST GIVE THIS COMMAND AFTER MAKING THE FTP
+          CONNECTION.
+
+   FTP DISABLE { MDTM, MLST, SIZE }
+          Disables implicit use of the given directive by GET or MGET in
+          case it causes problems; for example, because it makes
+          multifile downloads take too long or the server announces it
+          erroneously or misimplements it. Use DISABLE FEAT before making
+          a connection to prevent Kermit from sending the FEAT directive
+          as part of its initial sequence. Note that disabling FEAT,
+          SIZE, or MDTM does not prevent you from executing explicit FTP
+          FEATURES, FTP SIZE, or FTP MODTIME commands. Also note that
+          disabling SIZE prevents PUT /RESTART (recovery of interrupted
+          uploads) from working. YOU MUST GIVE THIS COMMAND AFTER MAKING
+          THE FTP CONNECTION.
+
+   To enable or disable more than one feature, use multiple FTP ENABLE or
+   FTP DISABLE commands. The SHOW FTP command shows which features are
+   currently enabled and disabled.
+
+   FTP FEATURES
+          This command sends a FEAT directive to the server. In case you
+          have been disabling and enabling different features, this
+          resynchronizes Kermit's feature list with the server's. If the
+          server does not support the FEAT directive, Kermit's feature
+          list is not changed.
+
+   FTP OPTIONS directive
+          Informational only: the server tells what options, if any, it
+          supports for the given directive, e.g. MLST. Fails if the
+          server does not support the OPTS directive or if the directive
+          for which options are requested is not valid. The directive is
+          case-insensitive.
+
+   FTP SIZE filename
+          Sends a SIZE directive to the server for the given file. The
+          filename must not contain wildcards. The server responds with
+          an error if the file can't be found, is not accessible, or the
+          SIZE directive is not supported, otherwise with the length of
+          the file in bytes, which Kermit displays and also makes
+          available to you in its \v(ftp_message) variable. If the
+          directive is successful, Kermit (re-)enables it for internal
+          use by the GET and MGET directives on this connection.
+
+   FTP MODTIME filename
+          Works just like the SIZE directive except it sends an MDTM
+          directive. Upon success, the server sends modification
+          date-time string, which Kermit interprets for you and also
+          makes available in its \v(ftp_message) variable.
+
+   Whenever a SIZE or MDTM directive is sent implicitly and rejected by
+   the server because it is unknown, Kermit automatically disables it.
+     _________________________________________________________________
+
+   3.11.3. Using MGET: NLST versus MLSD When you give an MGET command to
+   an FTP client, it sends a request to the FTP server for a list of
+   files, and then upon successful receipt of the list, goes through it
+   and issues a RETR (retrieve) directive for each file on the list (or
+   possibly only for selected files).
+
+   With the new FTP protocol extensions, now there are two ways to get
+   the list of files: the NLST directive, which has been part of FTP
+   protocol since the beginning, and the new MLSD directive, which is new
+   and not yet widely implemented. When NLST is used and you give a
+   command like "mget *.txt", the FTP client sends:
+
+NLST *.txt
+
+   and the server sends back a list of the files whose names match, e.g.
+
+foo.txt
+bar.txt
+baz.txt
+
+   Then when downloading each file, the client sends SIZE (if it wants
+   have a percent-done display) and MDTM (if it wants to set the
+   downloaded file's timestamp to match that of the original), as well as
+   RETR (to retrieve the file).
+
+   But when MLSD is used, the client is not supposed to send the filename
+   or wildcard to the server; instead it sends an MLSD directive with no
+   argument (or the name of a directory), and the server sends back a
+   list of all the files in the current or given directory; then the
+   client goes through the list and checks each file to see if it matches
+   the given pattern, the rationale being that the user knows only the
+   local conventions for wildcards and not necessarily the server's
+   conventions. So with NLST the server interprets wildcards; with MLSD
+   the client does.
+
+     The interpretation of NLST wildcards by the server is not
+     necessarily required or even envisioned by the FTP protocol
+     definition (RFC 959), but in practice most clients and servers work
+     this way. 
+
+   The principal advantage of MLSD is that instead of sending back a
+   simple list of filenames, it sends back a kind of database in which
+   each entry contains a filename together with information about the
+   file: type, size, timestamp, and so on; for example:
+
+size=0;type=dir;perm=el;modify=20020409191530; bin
+size=3919312;type=file;perm=r;modify=20000310140400; bar.txt
+size=6686176;type=file;perm=r;modify=20001215181000; baz.txt
+size=3820092;type=file;perm=r;modify=20000310140300; foo.txt
+size=27439;type=file;perm=r;modify=20020923151312; foo.zip
+(etc etc...)
+
+   (If the format of the file list were the only difference between NLST
+   and MLSD, the discussion would be finished: it would always be better
+   to use MLSD when available, and the MGET user interface would need no
+   changes. But there's a lot more to MLSD than the file-list format;
+   read on...)
+
+   The client learns whether the server supports MLSD in FEAT exchange.
+   But the fact that the server supports MLSD doesn't mean the client
+   should always use it. It is better to use MLSD:
+
+     * On connections where the server imposes a time penalty for every
+       command, e.g. the Red Hat Rawhide server. With MLSD, the client
+       needs to send only one command (RETR) per file, whereas NLST
+       requires three (SIZE, RETR, and MDTM). Suppose there is a
+       30-second delay for each command and 1000 files are to be fetched;
+       in that case, MLSD saves 60,000 seconds = 1000 minutes = 16 hours
+       and 40 minutes.
+     * For recursive downloads since there is no dependable way to
+       download directory trees with NLST.
+
+   But it is better to use NLST:
+
+     * If you want only a couple short files out of a large directory. In
+       this case, NLST is the better choice since the server sends a list
+       of only the files you want, not a list of (say) a million files,
+       which can make a big difference on slow connections. For example,
+       suppose your wildcard matches three files of 1K each, but the
+       million-file listing is 80MB long, and your connection is through
+       a modem. The overhead of using MLSD is practically infinite.
+     * If the server supports wildcarding features not known to the
+       client, but that can be used to achieve desirable effects
+       otherwise unobtainable, such as "[dir...]*.txt" in VMS or AOS/VS
+       "except" clauses.
+     * If you have been given a wildcard string by an FTP site
+       administrator for fetching a specific group of files out of a
+       larger directory, e.g. "mget ck[cuw]*.[cwh] makefile", that is
+       expected to work with any client (an FTP site administrator can't
+       be expected to know the wildcard syntax of every FTP client).
+
+   But when using MLSD there are complications:
+
+     * MLSD wants either a blank argument (meaning the current directory)
+       or else the name of a specific directory. The client must not send
+       it a wildcard or a filename.
+     * But if the user's command is "mget xxx", how does the client know
+       whether to send "xxx" in the MLSD directive? It might be the name
+       of a directory on on the server, in which case it should be sent,
+       or it might be the name of a file on the server (or a wildcard),
+       in which case it must not be sent. Since the client knows its own
+       wildcard syntax, then in most cases it would be right to send
+       "MLSD" with no argument if xxx is wild, and to send "MLSD xxx" if
+       it is not.
+     * But suppose the server's file system allows filename characters
+       that correspond with the client's wildcard syntax? For example:
+       "[abc]" could be either a valid VMS directory name or a wildcard
+       pattern used by the FTP client. What should the client do with
+       "mget [abc]"? In this case there must be a way for the user to
+       force sending the MGET argument as the MLSD argument.
+     * If "xxx" is a regular file in the server's current directory,
+       "mget xxx" works with NLST but not with MLSD.
+
+   To further complicate matters, NLST can (in theory) work just like
+   MLSD: if sent with a blank argument or a directory name, it is
+   supposed to return a complete list of files in the current or given
+   directory, which the client can match locally against some pattern. It
+   is not known if any FTP server or client does this but nevertheless,
+   it should be possible since this behavior can be inferred from RFC
+   959.
+
+   In view of these considerations, and given the need to preserve the
+   traditional FTP client command structure and behavior so the software
+   will be usable by most people:
+
+    1. The MGET command should produce the expected result in the common
+       cases, regardless of whether NLST or MLSD is used underneath.
+    2. For anomalous cases, the user needs a way to control whether the
+       MGET argument is sent to the server or kept for local use.
+    3. At the same time, the user might need a way to send a directory
+       name to the server, independent of any wildcard pattern.
+    4. The user needs a way to force NLST or MLSD for a given MGET
+       command.
+
+   By default, Kermit's MGET command uses MLSD if MLST is reported by the
+   server in its FEAT list. When MLSD is used, the filespec is sent to
+   the server if it is not wild (according to Kermit's own definition of
+   "wild" since it can't possibly know the server's definition). If the
+   filespec is wild it is held for local use to select files from the
+   list returned by the server. If MLST is not reported by the server or
+   is disabled, Kermit sends the MGET filespec with the NLST directive.
+
+   The default behavior can be overridden globally with FTP DISABLE MLST,
+   which forces Kermit to use NLST to get file lists. And then for
+   situations in which MLSD is enabled, the following MGET switches can
+   be used to override the defaults for a specific MGET operation:
+
+   /NLST
+          Forces the client to send NLST. Example:
+
+mget /nlst foo.*
+
+   /MLSD
+          Forces the client to send MLSD (even if MLST is disabled).
+          Example:
+
+mget /mlsd foo.*
+
+   /MATCH:pattern
+          When this switch is given, it forces the client to hold the
+          pattern for local use against the returned file list. If a
+          remote filespec is also given (e.g. the "blah" in "mget
+          /match:*.txt blah"), then it is sent as the NLST or MLSD
+          argument, presumably to specify the directory whose files are
+          to be listed. When the /MATCH switch is not given, the MGET
+          filespec is sent to the server if the directive is NLST or if
+          the filespec is not wild. Examples:
+
+  Command:                   With NLST:     With MLSD:
+    mget                      NLST           MLSD
+    mget *.txt                NLST *.txt     MLSD
+    mget foo                  NLST foo       MLSD foo
+    mget /match:*.txt         NLST           MLSD
+    mget /match:*.txt foo     NLST foo       MLSD foo
+
+   In other words, the pattern is always intepreted locally unless MGET
+   uses NLST and no /MATCH switch was given.
+     _________________________________________________________________
+
+   3.11.4. Examples
+
+  3.11.4.1. Downloading a Single File
+
+   There are no choices here, just use the FTP GET command. Kermit always
+   sends the RETR directive, and possibly SIZE and/or MDTM. The small
+   advantage of using MLST in this case is outweighed by the risk and
+   effort of coding a special case.
+
+  3.11.4.2. Downloading a Group of Files from a Single Directory
+
+   This case presents tradeoffs, especially on slow connections:
+
+     * For downloading all or most of the files in a directory, MLSD is
+       better because it eliminates the need to send SIZE and MDTM for
+       each file. No special actions are required in this case; Kermit
+       uses MLSD automatically if the server supports it (unless you have
+       disabled it).
+     * For a small number of files from a large directory, NLST is better
+       because it bypasses downloading of a potentially huge file list
+       prior to the files themselves. If you have a connection to a
+       server that supports MLSD, use the /NLST switch to force NLST:
+
+mget /nlst t[1234].h
+
+     * If the server supports MLSD but does not support separate SIZE or
+       MDTM directives, and you need the size and/or timestamp
+       information, MLSD is better; no special actions required.
+     * If the server supports MLSD but does not support the "size" and
+       "modify" facts, but it does support the SIZE or MDTM directives,
+       and you need the size and/or timestamp information, NLST is
+       better.
+
+  3.11.4.3. Downloading a Directory Tree
+
+   MLSD is the only choice for recursive downloads; they rarely, if ever,
+   work with NLST (the few cases where they do work rely on
+   extra-protocol "secret" notations for the NLST argument). No special
+   actions are required to force MLSD when the server supports it, unless
+   you have disabled it. Examples:
+
+   MGET /RECURSIVE
+          This tells the server to send all files and directories in the
+          tree rooted at its current directory.
+
+   MGET /RECURSIVE *.txt
+          This tells the server to send all *.txt files in the tree
+          rooted at its current directory.
+
+   MGET /MLSD /RECURSIVE *.txt
+          Same as the previous example but forces Kermit to send MLSD in
+          case it was disabled, or in case the server is known to support
+          it even though it did not announce it in its FEAT listing.
+
+   MGET /RECURSIVE /MATCH:*.zip archives
+          Tells the server to send all ZIP files in the tree rooted at
+          its "archives" directory.
+
+   MGET /RECURSIVE /MATCH:* [abc]
+          The server is running on VMS and you want it to send all the
+          files in the directory tree rooted at [ABC]. But since "[abc]"
+          looks just like a wildcard, you have to include a /MATCH:
+          switch to force Kermit to send "[abc]" as the MLSD argument.
+
+   In all cases in which the /RECURSIVE switch is included, the server's
+   tree is duplicated locally.
+
+     Although MLSD allows recursion and NLST does not, the MLSD
+     specification places a heavy burden on the client; the obvious,
+     straightforward, and elegant implementation (depth-first, the one
+     that Kermit currently uses) requires as many open temporary files
+     as the server's directory tree is deep, and therefore client
+     resource exhaustion -- e.g. exceeding the maximum number of open
+     files -- is a danger. Unfortunately MLSD was not designed with
+     recursion in mind. (Breadth-first traversal could be problematic
+     due to lack of sufficient navigation information.) 
+
+   Of course all of Kermit's other MGET switches can be used too, e.g.
+   for finer-grained file selection (by date, size, etc), for moving or
+   renaming files as they arrive, to override Kermit's automatic per-file
+   text/binary mode switching, to pass the incoming files through a
+   filter, to convert text-file character sets, and so on.
+
+  3.11.4.4. NLST/MLSD Summary Table
+
+   Here's a table summarizing MGET behavior when the server supports both
+   NLST and MLSD. /NLST and /MLSD switches are included for clarity to
+   indicate which protocol is being used, and the expected effects. In
+   practice you can omit the /NLST and /MLSD switches and the Kermit
+   client chooses the appropriate or desired protocol as described above.
+   Sample commands presume a Unix file system on the server, but of
+   course the server can have any file system or syntax at all.
+
+   User's Command FTP Sends Remarks
+   mget /nlst NLST Gets a list of all the files in the server's current
+   and downloads each file. The list includes names only, so Kermit also
+   must send SIZE and MDTM directives if size and timestamp information
+   is required (this is always true of NLST). Sending NLST without an
+   argument is allowed by the RFC959 NLST definition and by the Kermit
+   FTP client, but might not work with other clients, and also might not
+   work with every server.
+   mget /nlst foo NLST foo If "foo" is a directory, this gets a list of
+   all the files from the server's "foo" directory and downloads each
+   file; otherwise this downloads the file named "foo" (if any) from the
+   server's current directory.
+   mget /nlst *.txt NLST *.txt Gets a list of the files in the server's
+   current directory whose names match the pattern *.txt, and then
+   downloads each file from the list. Because we are using NLST, we send
+   the filespec (*.txt) to the server and the server interprets any
+   wildcards.
+   mget /nlst foo/*.txt NLST foo/*.txt  Gets a list of the files in the
+   server's "foo" directory whose names match the pattern *.txt, and then
+   downloads each file from the list (server interprets wildcards).
+   mget /nlst /match:*.txt NLST Gets a list of all the files in the
+   server's current directory and then downloads each one whose name
+   matches the pattern *.txt (client interprets wildcards).
+   mget /nlst /match:*.txt foo  NLST foo Gets a list of all the files in
+   the server's "foo" directory and then downloads each one whose name
+   matches the pattern *.txt (client interprets wildcards).
+   mget /mlsd MLSD Gets a list of all the files from the server's current
+   directory and then downloads each one. The list might include size and
+   timestamp information, in which case Kermit does not need to send SIZE
+   and MDTM directives for each file (this is always true of MLSD).
+   mget /mlsd foo MLSD foo Gets a list of all the files from the server's
+   "foo" directory (where the string "foo" does not contain wildcards)
+   and then downloads each one. If "foo" is a regular file and not a
+   directory, this command is supposed to fail, but some servers have
+   been observed that send the file.
+   mget /mlsd *.txt MLSD Gets a list of all the files from the server's
+   current directory and then downloads only the ones whose names match
+   the pattern "*.txt". Because we are using MLSD and the MGET filespec
+   is wild, we do not send the filespec to the server, but treat it as
+   though it had been given in a /MATCH: switch and use it locally to
+   match the names in the list.
+   mget /mlsd foo/*.txt MLSD This one won't work because MLSD requires
+   that the notions of server directory and filename-matching pattern be
+   separated. However, the client, which can't be expected to know the
+   server's file-system syntax, winds up sending a request that the
+   server will (or should) reject.
+   mget /mlsd /match:*.txt MLSD Gets a list of all the files from the
+   server's current directory and then downloads only the ones whose
+   names match the pattern "*.txt" (client interprets wildcards).
+   mget /mlsd /match:*.txt foo MLSD foo If "foo" is a directory on the
+   server, this gets a list of all the files from the server's "foo"
+   directory and then downloads only the ones whose names match the
+   pattern "*.txt" (client interprets wildcards). This leaves the server
+   CD'd to the "foo" directory; there's no way the client can restore the
+   server's original directory because MLSD doesn't give that
+   information, and since the client can not be expected to know the
+   server's file-system syntax, it would not be safe to guess. If "foo"
+   is a regular file, MLSD fails.
+   mget /mlsd foo bar MLSD This one is problematic. You're supposed to be
+   able to give MGET a list a filespecs; in this case we name two
+   directories. The client must change the server's directory to "foo" to
+   get the list of files, and then the files themselves. But then it has
+   no way to return to the server's previous directory in order to do the
+   same for "bar", as explained in the previous example.
+   mget /mlsd /match:* [abc] MLSD [abc] Including a /MATCH: switch forces
+   [abc] to be sent to the server even though the client would normally
+   think it was a wildcard and hold it for local interpretation. In this
+   example, [abc] might be a VMS directory name.
+   mget /mlsd /match:* t*.h MLSD t*.h Contrary to the MLSD specification,
+   some MLSD-capable FTP servers do interpret wildcards. This form of the
+   MGET command can be used to force a wildcard to be sent to the server
+   for interpretation.
+
+   When MLSD is used implicitly (that is, without an /MLSD switch given
+   to force the use of MLSD) and an MGET command such as "mget foo/*.txt"
+   fails, Kermit automatically falls back to NLST and tries again.
+     _________________________________________________________________
+
+   3.11.5. References
+
+    1. Postel, J., and J. Reynolds, File Transfer Protocol (FTP), RFC
+       959, October 1985: [361]ftp://ftp.isi.edu/in-notes/rfc959.txt.
+    2. Hethmon, P, and R. Elz, Feature negotiation mechanism for the File
+       Transfer Protocol, RFC 2389, August 1998:
+       [362]ftp://ftp.isi.edu/in-notes/rfc2389.txt.
+    3. Elz, R, and P. Hethmon, Extensions to FTP, Internet Draft
+       draft-ietf-ftpext-mlst-16.txt, September 2002:
+       [363]http://www.ietf.org/internet-drafts/draft-ietf-ftpext-mlst-16
+       .txt.
+    4. [364]The Kermit FTP Client (overview).
+
+   [ [365]Top ] [ [366]FTP Top ] [ [367]C-Kermit Home ] [ [368]Kermit
+   Home ]
+  __________________________________________________________________________
+
+4. FILE SCANNING
+
+   A new feature called file scanning is used in various contexts to
+   determine if a file is text or binary, and if it is text, what kind of
+   text. The overhead of file scanning is surprisingly tolerable, usually
+   about a quarter second per file. File scanning is now used instead of
+   filename patterns unless you SET FILE SCAN OFF, which restores the
+   previous behavior.
+
+   The primary benefit of file scanning is in file transfer. For all
+   practical purposes, now you can stop worrying about whether a file
+   should be sent in binary or text mode, or about sending mixtures of
+   text and binary files in a single operation, or configuring and
+   fine-tuning your lists of binary-file and text-file name patterns: now
+   it all just works.
+
+   File scanning is done by the file sender, which determines the type of
+   each file before it sends it and informs the receiver (Kermit or FTP
+   server) of the type. File scanning is NOT done by the receiver,
+   because it is the sender's responsibility to determine each file's
+   type, send the file in the right mode, and inform the receiver of the
+   mode. If both transfer partners are capable of this (or any other)
+   form of automatic text/binary mode switching, then files can be sent
+   in both directions with no worries about corruption due to
+   inappropriate transfer mode. (As noted in [369]Section 3, FTP servers
+   don't do this, so this discussion does not apply when using Kermit to
+   download from an FTP server.)
+
+   The rest of this section is mainly for the curious. If you don't read
+   it and simply accept all defaults, every file you send should go in
+   the appropriate mode automatically. As always, however, for
+   character-set translation to work for 7- and 8-bit character-set
+   files, the appropriate SET FILE CHARACTER-SET command(s) must have
+   been executed to identify their encoding (Kermit's default file
+   character-set is neutral ASCII except on platforms like HP-UX or
+   DG/UX, where the default file character-set is known). And of course,
+   receiving is another matter -- obviously the other Kermit must also
+   send each file in the appropriate mode.
+
+   Scanning is more reliable than filename patterns simply because
+   filenames are not reliable indicators of the file's contents. Classic
+   examples include ".doc" files, which are binary if Microsoft Word
+   documents but text on most other platforms, and ".com" files, which
+   are binary on DOS and Windows but text on VMS. Anyway, nobody knows
+   the naming conventions (if any) of all the applications (and persons!)
+   on your computer. Scanning, on the other hand, determines each file's
+   type by inspecting its contents rather than just looking at its name.
+
+   Also, file patterns -- even when they work as intended -- categorize
+   each file only as text or binary, whereas file scanning can make finer
+   distinctions:
+
+   BINARY
+          Binary data, not to be converted in any way. Examples include
+          binary machine code (executable programs), graphics images
+          (GIF, JPG, etc), compressed files (Z, GZ, etc), archives and
+          packages (ZIP, TAR, RPM, etc), object files and libraries (OBJ,
+          DLL, etc).
+
+   7-BIT TEXT
+          Text encoded in a 7-bit character set such as ASCII or one of
+          the ISO 646 national versions. Kermit has no way to tell which
+          character is used, only that it's 7-bit text. Typical examples
+          include program source code, README files, Perl or Kermit
+          scripts, plain-text email, HTML, TeX, and various textual
+          encodings of binary files: Hex, Base64, etc. When sending such
+          files, the FILE DEFAULT 7BIT-CHARACTER-SET is used as the file
+          character-set, and then the appropriate transfer character set
+          is chosen from the associations list (ASSOCIATE, SHOW
+          ASSOCIATIONS).
+
+   8-BIT TEXT
+          Text encoded in an 8-bit character set such as Latin-1,
+          Latin-2, Latin/Hebrew, Latin/Cyrillic, KOI8, HP-Roman8, JIS X
+          0208, Code Page 437, or Code Page 1252. Again, Kermit has no
+          way of knowing which particular set is in use, only that it's
+          8-bit text. When sending such files, the FILE DEFAULT
+          8BIT-CHARACTER-SET is used as the file character-set, and then
+          the appropriate transfer character set is chosen from the
+          associations list.
+
+   UCS2 TEXT
+          Unicode in its basic form, 16 bits (2 octets) per character.
+          When sending such files, UCS2 is the file character-set and the
+          byte order is identified automatically; the appropriate
+          transfer character set is chosen from the associations list.
+          Normally this would be UTF8. UTF-16 is not supported yet;
+          Kermit's Unicode translations are restricted to Plane 0, the
+          Base Multilingual Plane (BMP).
+
+   UTF8 TEXT
+          Unicode in its 8-bit transformation format. When sending such
+          files, UTF8 is the file character-set; the appropriate transfer
+          character set is chosen from the associations list, normally
+          UCS2 or UTF8.
+
+   File scanning is available in UNIX C-Kermit, in K-95, and to a limited
+   extent, in VMS C-Kermit (full scanning is problematic in VMS because
+   even plain-text files might contain binary record-format information).
+   The relevant commands are:
+
+   SET TRANSFER MODE { AUTOMATIC, MANUAL }
+          Tells whether the file-transfer mode (text or binary) should be
+          set by automatic or "manual" means. AUTOMATIC is the default,
+          which allows any of the automatic methods that are enabled to
+          do their jobs: FILE SCAN, FILE PATTERNS, peer recognition, etc.
+          MANUAL lets you control the transfer mode with the SET FILE
+          TYPE commands. As always, /TEXT and /BINARY switches on your
+          file-transfer commands override all other methods; if you give
+          one of these switches, scanning is not done. SHOW TRANSFER
+          displays the current TRANSFER MODE setting.
+
+   SET FILE SCAN { ON [ number ], OFF }
+          Turns this feature on and off. It's ON by default. When OFF,
+          the previous rules apply (SET FILE PATTERNS, etc). When ON is
+          given, you can also specify a number of bytes to be scanned.
+          The default is 49152 (= 48K). If a negative number is given,
+          the entire file is scanned, no matter how big, for maximum
+          certainty (for example, a PostScript file that appears to be
+          plain text might include an embedded graphic past the normal
+          scanning limit). SHOW FILE displays the current FILE SCAN
+          setting.
+
+   SET FILE DEFAULT 7BIT-CHARACTER-SET name
+          Tells the 7-bit character-set to use if scanning identifies a
+          7-bit text file, e.g. GERMAN. SHOW FILE displays the current
+          SET FILE DEFAULT settings. So does SHOW CHARACTER-SETS.
+
+   SET FILE DEFAULT 8BIT-CHARACTER-SET name
+          Tells the 8-bit character-set to use if scanning identifies an
+          8-bit text file, e.g. LATIN1. SHOW FILE and SHOW CHARACTER-SET
+          display this.
+
+   ASSOCIATE FILE-CHARACTER-SET fcs tcs
+          When sending files and a file character-set (fcs) is identified
+          by scanning, this tells C-Kermit which transfer character-set
+          (tcs) to translate it to. It also allows C-Kermit to set the
+          appropriate transfer character-set automatically whenever you
+          give a SET FILE CHARACTER-SET command.
+
+   ASSOCIATE TRANSFER-CHARACTER-SET tcs fcs
+          When receivinging files and a file arrives whose transfer
+          character-set (tcs) is announced by the sender, this command
+          tells C-Kermit which file character-set (fcs) to translate it
+          to. It also allows C-Kermit to set the appropriate file
+          character-set whenever you give a SET TRANSFER CHARACTER-SET
+          command.
+
+   SET FILE CHARACTER-SET name
+          When given for a 7-bit set, also sets FILE DEFAULT
+          7BIT-CHARACTER-SET to the same set. When given for an 8-bit
+          set, also sets FILE DEFAULT 8BIT-CHARACTER-SET to the same set.
+          If an ASSOCIATE FILE-CHARACTER-SET command has been given for
+          this set, also sets the corresponding transfer character-set.
+
+   DIRECTORY /XFERMODE [ filespec ]
+          Performs a file scan of the given files, listing the result for
+          each file. If FILE SCAN is OFF but PATTERNS are ON, the result
+          shown according to the current FILE TEXT-PATTERNS and
+          BINARY-PATTERNS, and are restricted to (B) and (T). When FILE
+          SCAN is ON, the results are:
+
+  (B)          Binary
+  (T)(7BIT)    Text: 7-bit
+  (T)(8BIT)    Text: 8-bit
+  (T)(UTF8)    Text: Unicode UTF8
+  (T)(UCS2BE)  Text: Unicode UCS2 Big Endian
+  (T)(UCS2LE)  Text: Unicode UCS2 Little Endian
+
+          So you can use DIR /XFER to get a preview of how each file in a
+          selected group will be transferred. Everything to the right of
+          the (B) or (T) is new. If FILE SCAN is OFF, you only get the
+          (B) or (T) as before.
+
+          Note: Big and Little Endian refer to the ordering of bytes
+          within a computer word. Big Endian architecture is standard and
+          is used on most non-PC computers. Little Endian architecture is
+          used on PCs.
+
+   To illustrate file-transfer with scanning, suppose you have a
+   directory containing a mixture of text and binary files, and each text
+   file can be 7-bit German ISO 646, 8-bit Latin-1, or Unicode in any of
+   the following forms: UCS2 Little Endian, UCS2 Big Endian, or UTF8
+   ([370]UTF-16 is not supported yet). Assuming all the built-in defaults
+   are in effect, the following three commands do the job:
+
+  set file char german   ; This sets the default for 7-bit text files
+  set file char latin1   ; This sets the default for 8-bit text files
+  send *
+
+   Each file is sent in the appropriate mode (text or binary), with text
+   files converted to the appropriate transfer character-set and labeled
+   so the receiver can convert them according to its own local
+   conventions.
+
+   By the way, what if you want to inhibit character-set translation but
+   still allow automatic text/binary mode switching? Previously, you
+   could simply SET TRANSFER CHARACTER-SET TRANSPARENT. But now with file
+   scanning, the file and transfer character-sets are set automatically
+   per file. A new command was added for this purpose:
+
+   SET TRANSFER TRANSLATION { ON, OFF }
+          Enables and disables file-transfer character-set translation.
+          It is enabled by default.
+
+   When TRANSFER TRANSLATION is OFF but FILE SCAN is ON, files are still
+   scanned to see if they are text or binary, but no character-set
+   translation is done when they text: only the normal record-format
+   conversion.
+
+   Like all SET commands, SET TRANSFER TRANSLATION is global and
+   persistent. You can also force a particular file-transfer command
+   (SEND, MSEND, GET, RECEIVE, TRANSMIT, etc) to not translate without
+   affecting the global translation settings by including the new
+   /TRANSPARENT switch, e.g.
+
+  send /transparent oofa.txt
+
+   As of C-Kermit 8.0.206, SET TRANSFER CHARACTER-SET TRANSPARENT implies
+   SET TRANSFER TRANSLATION OFF.
+
+   File scanning is also used in the TYPE command. The source file type
+   and character set are determined as above, and then the file is
+   automatically converted to your display character-set, line by line.
+   In Kermit 95, the display character-set is Unicode, perhaps converted
+   to your current console code page; in other versions of C-Kermit, it
+   is your current file character-set. Thus if you have the following set
+   appriately:
+
+  SET FILE CHARACTER-SET (necessary in Unix but not K95)
+  SET FILE DEFAULT 7BIT CHARACTER-SET
+  SET FILE DEFAULT 8BIT CHARACTER-SET
+
+   then you should be able to TYPE any text file and see something
+   reasonable. For example, in Unix, if your DEFAULT 7BIT-CHARACTER-SET
+   is ITALIAN and your DEFAULT 8BIT-CHARACTER-SET is LATIN1, and your
+   FILE CHARACTER-SET is LATIN1, you can TYPE an Italian ISO 646 file, a
+   Latin-1 file, or any kind of Unicode file, and have it translated
+   automatically to Latin-1 for your display.
+
+   In the GUI version of Kermit 95, you can see mixtures of many
+   different scripts if the file is UTF8 or UCS2: Roman, Cyrillic,
+   Hebrew, Greek, Armenian, Georgian, etc, all on the same screen at
+   once.
+
+   File scanning also adds a new criterion for file selection, i.e. to
+   select only text (or binary) files. Several commands now include a new
+   switch, /TYPE:{BINARY,TEXT,ALL}. BINARY means select only binary
+   regular files (not directories). TEXT means select only text files.
+   ALL means don't scan; select all files. Examples:
+
+   SEND /TYPE:BINARY *.*
+          Sends only binary files, skipping over text files.
+
+   NOTE: File scanning is NOT done when using external protocols (because
+   the external protocol programs, such as sz, are processing each file,
+   not Kermit).
+
+   DIRECTORY /TYPE:TEXT
+          Lists only text files but not binary files.
+
+   DELETE /TYPE:BINARY foo.*
+          Deletes all foo.* files that are regular binary files but does
+          not delete any text files.
+
+   CHMOD /TYPE:BINARY 775 *
+          (UNIX) Changes the permissions of all binary files to 775.
+
+   When FILE SCAN is OFF and FILE PATTERNS are ON, behavior is as before
+   with PATTERNS ON, but with some improvements:
+
+     * Pathnames are now stripped prior to pattern matching.
+     * Backup suffixes (like .~3~) are stripped prior to pattern
+       matching.
+
+   [ [371]Top ] [ [372]Contents ] [ [373]C-Kermit Home ] [ [374]Kermit
+   Home ]
+  __________________________________________________________________________
+
+5. FILE AND DIRECTORY NAMES CONTAINING SPACES
+
+   Prior to the introduction of the graphical user interface (GUI), it
+   was inconceivable that file or directory names could contain spaces,
+   because space is a field delimiter in all command languages. GUIs,
+   however, use dialog boxes for filenames, so there is never any
+   question of distinguishing a filename from adjacent fields -- because
+   there are no adjacent fields -- and therefore it has become quite
+   common on computers that have GUIs to have file and directory names
+   composed of multiple words. Of course this poses problems for command
+   shells and other text-oriented programs.
+
+   Most command shells address these problems by allowing such names to
+   be enclosed in doublequotes, e.g.:
+
+  cd "c:\Program Files"
+
+   C-Kermit previously used braces for this:
+
+  cd {c:\Program Files}
+
+   which was not what most people expected. And even when braces were
+   used, Kermit had difficulties with completion, file menus, and so
+   forth, within braced fields.
+
+   C-Kermit 8.0 allows either doublequotes or braces to be used for
+   grouping:
+
+  send "this file"
+  send {this file}
+  rename "this file" "that file"
+  rename {this file} "that file"
+  rename "this file" {that file}
+  cd {Program Files}
+  cd "Program Files"
+
+   Note that the doublequotes or brackets must enclose the whole file or
+   directory specification:
+
+  "c:\My Directory"
+
+   not:
+
+  c:\"My Directory"
+
+   In C-Kermit 8.0, you can also use completion on these filenames, in
+   which case Kermit supplies the quotes (or braces) automatically.
+   Example (in which the current directory contains only one file whose
+   name starts with "th" and its full name is "this file" (without the
+   quotes, but with the space)):
+
+  cat th<Tab>
+
+   Kermit repaints the filename field like this:
+
+  cat "this file"
+
+   That is, it backspaces over the original "th" and then writes the
+   filename in doublequotes.
+
+   If completion is only partial, Kermit still supplies the quotes, but
+   in this case also beeps. To continue the filename, you must first
+   backspace over the closing quote. The closing quote is supplied in
+   this case to make sure that you can see the spaces, especially if they
+   are trailing. For example, if the current directory contains two files
+   whose names start with "th", and their fill names are "this file" and
+   "this other file":
+
+  cat th<Tab>
+
+   Kermit prints:
+
+  cat "this "<Beep>
+
+   If it didn't print the closing quote, you would probably wonder why it
+   was beeping.
+
+   Also, if you begin a filename field with a doublequote or opening
+   brace, now you can use completion or get ?-help; this was never
+   possible before.
+
+ C-Kermit>type "thi? Input file specification, one of the following:
+   this file        this other file
+ C-Kermit>type "thi_
+
+   [ [375]Top ] [ [376]Contents ] [ [377]C-Kermit Home ] [ [378]Kermit
+   Home ]
+  __________________________________________________________________________
+
+6. OTHER COMMAND PARSING IMPROVEMENTS
+
+  6.1. Grouping Macro Arguments
+
+   Doublequotes now can be used in macro invocations to group arguments
+   containing spaces, where previously only braces could be used:
+
+  define xx show args
+  xx one "this is two" three
+
+   Result:
+
+  Macro arguments at level 0 (\v(argc) = 4):
+   \%0 = xx
+   \%1 = one
+   \%2 = this is two
+   \%3 = three
+
+   Also, you can now quote braces and quotes in macro args (this didn't
+   work before). Examples:
+
+  xx "{"  ; The argument is a single left brace
+  xx {"}  ; The argument is a doublequote character
+
+   In case this new behavior interferes with your scripts, you can
+   restore the previous behavior with:
+
+  SET COMMAND DOUBLEQUOTING OFF
+
+  6.2. Directory and File Name Completion
+
+   C-Kermit 8.0 also includes better completion for directory names, e.g.
+   in the CD command. If the name typed so far uniquely matches a
+   directory name, it is completed (as before), but now if the directory
+   contains any subdirectories, completion is partial (allowing you to
+   supply additional path segments without backspacing); otherwise it is
+   complete.
+
+   Completion has also been improved for file and directory names that
+   contain not only spaces (as described above) but also "metacharacters"
+   such as asterisk (*) and tilde (~): now the field is repainted if
+   necessary. For example, if the current directory contains only one
+   file whose name contains "blah", then in:
+
+  type *blah<Tab>
+
+   "*blah" is replaced by the filename. In earlier releases, the part
+   typed so far was left on the command line (and in the history buffer),
+   so even when the original command worked, the recalled version would
+   not. Similarly for ~ (the nearly-universal Unix notation for
+   username):
+
+  type ~olga/x<Tab>
+
+   is repainted as (e.g.):
+
+  type /users/home/olga/x(Beep)
+
+   Speaking of command history, the new SHOW HISTORY command shows your
+   command history and recall buffer. SAVE COMMAND HISTORY saves it into
+   a file of your choice.
+
+  6.3. Passing Arguments to Command Files
+
+   The method for passing arguments to command files has been improved.
+   Prior to C-Kermit 7.0 there was no provision for doing this. In
+   C-Kermit 7.0, the TAKE command was changed to allow arguments to be
+   given after the filename:
+
+  take commandfile arg1 arg2 ...
+
+   This was accomplished by replacing the current \%1, \%2, etc, with the
+   given arguments, since a new set of macro argument variables is
+   created only when a macro is executed, not a command file. It is much
+   more intuitive, however, if arguments to command files worked like
+   those to macros: the command file sees the arguments as its own \%1,
+   \%2, etc, but the caller's variables are not disturbed. C-Kermit 8.0
+   accomplishes this by automatically creating an intermediate temporary
+   macro to start the command file (if any arguments were given), thus
+   creating a new level of arguments as expected.
+
+  6.4. More-Prompting
+
+   The familiar --more?-- prompt that appears at the end of each
+   screenful of command-response output now accepts a new answer: G (Go)
+   meaning "show all the rest without pausing and asking me any more
+   questions". P (Proceed) is a synonym for G.
+
+  6.5. Commas in Macro Definitions
+
+   As noted in the [379]C-Kermit manual, comma is used to separate
+   commands in a macro definition. Even when the macro is defined on
+   multiple lines using curly-brace block-structure notation without
+   commas, the definition is still stored internally as a comma-separated
+   list of commands. Therefore special tricks are needed to include a
+   comma in a command. The classic example is:
+
+  define foo {
+      (some command)
+      if fail echo Sorry, blah failed...
+  }
+
+   This would result in Kermit trying to execute a "blah" command. This
+   could always be handled by enclosing the text in braces:
+
+  define foo {
+      (some command)
+      if fail echo {Sorry, blah failed...}
+  }
+
+   but doublequotes (more intuitive) should have worked too. Now they do:
+
+  define foo {
+      (some command)
+      if fail echo "Sorry, blah failed..."
+  }
+
+  6.6. Arrow Keys
+
+   As of version 8.0.201, C-Kermit on most platforms lets you access the
+   command history buffer with arrow keys, just as you always could with
+   control characters. The restrictions are:
+
+    1. Only Up and Down arrow keys are accepted.
+    2. Only 7-bit ANSI arrow-key sequences are understood (ESC followed
+       by [ or uppercase letter O, followed by uppercase letter A or (up)
+       B (down).
+
+   This change was made to facilitate command recall in Linux-based PDAs
+   that don't have a Control key, or at least not one that's easily (or
+   always) accessible, such as the Sharp Zaurus SL5500.
+
+   [ [380]Top ] [ [381]Contents ] [ [382]C-Kermit Home ] [ [383]Kermit
+   Home ]
+  __________________________________________________________________________
+
+7. NEW COMMANDS AND SWITCHES
+
+   See [384]Section 4 for more about file scanning and the /TYPE: switch.
+
+   ASK[Q] [ /TIMEOUT:number /QUIET /DEFAULT:text ] variable [ prompt ]
+          The new optional /TIMEOUT: switch for ASK and ASKQ causes the
+          command to time out and and fail if no response is given within
+          the specified number of seconds, 1 or greater (0 or less means
+          no timeout, wait forever). This works just like SET ASK-TIMER,
+          except its effect is local to the ASK command with which it is
+          given and it does not disturb the global ask timer setting. The
+          new /QUIET switch tells Kermit not to print an error message if
+          the ASK or ASKQ command times out waiting for a response.
+
+          Version 8.0.211 adds the /DEFAULT:text switch for ASK-Class
+          commands (ASK, ASKQ, and GETOK). This lets you supply a default
+          answer in case the user supplies an empty answer or the
+          /TIMEOUT: switch was included and the time limit expired
+          without an answer. In both these cases, the command succeeds.
+
+   CAT filename
+          Equivalent to TYPE /NOPAGE.
+
+   CDUP
+          Changes Kermit's local working directory to the parent of the
+          current one. Equivalent to "cd .." in UNIX or Windows, "cd [-]"
+          in VMS, "cd ^" in AOS/VS, etc; in other words, it's a
+          platform-independent way of moving one level up in a directory
+          tree.
+
+   CHMOD [ switches ] permission files
+          UNIX only. Sets file permissions for one or more files or
+          directories. The permission must be given as an octal number,
+          e.g. 664, 755. Switches: /DIRECTORIES, /FILES, /NOLIST, /PAGE,
+          /DOTFILES, /LIST, /NOPAGE, /RECURSIVE, /TYPE:{TEXT,BINARY,ALL},
+          /SIMULATE. The /TYPE: switch allows selection of only text or
+          binary files. For example, if you have a mixture of source
+          files and executables, you can use "chmod /files /type:text
+          664" to give owner/group read/write and world read permission
+          to the text files, and "chmod /files /type:binary 775" to give
+          the same plus execute permission to the executables. Use
+          /SIMULATE to see which files would be affected, without
+          actually changing their permissions.
+
+   CLEAR KEYBOARD-BUFFER
+          Flushes any as-yet unread characters from the keyboard input
+          buffer. Useful for flushing typeahead in scripts.
+
+   CONTINUE
+          When given at an interactive command prompt that was reached by
+          issuing a PROMPT command (described in this section) from a
+          script, this command returns to the script, continuing its
+          execution at the command after the PROMPT command. In this
+          context, CONTINUE is simply a more-intuitive synonym for END.
+
+   COPY, RENAME, and TRANSLATE
+          These commands now work on file groups if the target filename
+          is a directory, e.g. "copy oofa.* ..", "rename * ~olga/tmp/"
+
+   COPY /APPEND source destination
+          The source file specification can now include wildcards, in
+          which case all of the source files that match will go into the
+          destination file in alphabetical order by name.
+
+   DELETE /ASK
+          Asks permission to delete each file before deleting it. In
+          C-Kermit 7.0, the answers were "yes" (or "ok") and "no".
+          C-Kermit 8.0 adds "go" (meaning, delete all the rest without
+          asking) and "quit" (cancel the DELETE command and return to the
+          prompt).
+
+   DELETE /DIRECTORIES
+          Deletes not only files but also directories.
+
+   DELETE /RECURSIVE
+          Deletes all files that match the given file specification in
+          the current (or given) directory and all directories beneath
+          it.
+
+   DELETE /SUMMARY
+          Prints only the number of files deleted and total size freed,
+          without listing each file.
+
+   DELETE /TREE
+          Shorthand for DELETE /RECURSIVE /DIRECTORIES /DOTFILES/.
+          Equivalent to Windows DELTREE or Unix "rm -Rf". If no file
+          specification is given, the contents of the current directory,
+          plus all of its subdirectories and their contents, are deleted.
+
+   DELETE /TYPE:BINARY
+          Delete only regular binary files (requires FILE SCAN ON).
+
+   DELETE /TYPE:TEXT
+          Delete only regular text files (requires FILE SCAN ON).
+
+   DIRECTORY [ switches ] [ filespec [ filespec [ filespec ... ] ] ]
+          The DIRECTORY command now accepts more than one file
+          specification; e.g. "directory moon.txt sun.doc stars.*".
+
+   DIRECTORY /NORECURSIVE xxx
+          If xxx is a directory name, forces listing of the directory
+          itself rather than its contents.
+
+   DIRECTORY /FOLLOWLINKS xxx
+          (UNIX only) Tells the DIRECTORY command to follow symbolic
+          links. This not the default because it can cause endless loops.
+
+   DIRECTORY /NOFOLLOWLINKS xxx
+          (UNIX only) Tells the DIRECTORY command not to follow symbolic
+          links, but rather, merely to list them. This is the default.
+
+   DIRECTORY /OUTPUT:filename
+          Sends the results of the DIRECTORY command to the given file.
+
+   DIRECTORY /SUMMARY
+          Prints only the number of directories and files and the total
+          size, without listing each file.
+
+   DIRECTORY /TYPE:{TEXT,BINARY}
+          Shows only files of the selected type, based on file scan.
+
+   DIRECTORY /XFERMODE
+          Now shows results of file scan (see [385]Section 4).
+
+   FOPEN [ switches ] channel filename
+
+          As of version 8.0.211, FOPEN allows /dev/tty as a filename in
+          Unix-based operating systems.
+
+   FREAD /TRIM
+          (8.0.211) Trims any trailing blanks or tabs from the item (such
+          as a line of text) that it has read.
+
+   FREAD /UNTABIFY
+          (8.0.211) Converts Horizontal Tab characters to the appropriate
+          number of spaces, based on VT100-like tab stops
+          (1,9,17,25,...).
+
+   GREP [ switches ] pattern files
+          Similar to Unix grep command: displays file lines that match
+          the given [386]pattern. Switches:
+
+        /COUNT[:variable]
+                Don't show the matching lines, just tell how many lines
+                match. If a variable name is specified, the count is
+                stored in the given variable.
+
+        /DOTFILES
+                Include files whose names begin with dot.
+
+        /LINENUMBERS
+                Show line numbers of matching lines.
+
+        /NAMEONLY
+                only list the names of files that contain matching lines,
+                but not the lines themselves.
+
+        /NOBACKUP
+                Skip backup files.
+
+        /NOCASE
+                Ignore alphabetic case while pattern matching.
+
+        /NODOTFILES
+                skip files whose names start with dot (period).
+
+        /NOLIST
+                Suppress output but set SUCCESS or FAILURE according to
+                search result.
+
+        /NOMATCH
+                Look for lines that do not match the pattern.
+
+        /NOPAGE
+                Don't pause between screens of output.
+
+        /OUTPUT:filename
+                Write results into the given file.
+
+        /PAGE
+                Pause between screens of output.
+
+        /RECURSIVE
+                Search files in subdirectories too.
+
+        /TYPE:{TEXT,BINARY}
+                Search only files of the specified type.
+
+          Synonyms: FIND, SEARCH.
+
+   GETOK /TIMEOUT:n /QUIET /DEFAULT:text
+          The new /QUIET switch instructs GETOK, when given a timeout,
+          not to print an error message if it times out. As of 8.0.211, a
+          default answer can be supplied (see ASK).
+
+   HEAD [ switches ] filename
+          Equivalent to TYPE /HEAD [ other-switches ] filename.
+
+   HELP DATE
+          Explains date-time formats, including timezone notation and
+          delta times.
+
+   HELP FIREWALLS
+          Explains the firewall negotiation capabilities of your version
+          of Kermit.
+
+   KCD [ symbolic-directory-name ]
+          Changes Kermit's working directory to the named symbolic
+          directory, such as such as exedir, inidir, startup, download,
+          or and home. Type "kcd ?" for a list of symbolic directory
+          names known to your copy of Kermit, or give the new ORIENTATION
+          command for a more detailed explanation. If you give a KCD
+          command without a directory name, Kermit returns to its "home"
+          directory, which is determined in some way that depends on the
+          underlying operating system, but which you can redefine with
+          the (new) SET CD HOME command. Your home directory is shown by
+          SHOW CD and it's also the value of the \v(home) variable.
+
+   LICENSE
+          Displays the C-Kermit license.
+
+   L-commands
+          When Kermit has a connection to a Kermit or FTP server, file
+          managment commands such as CD, DIRECTORY, and DELETE might be
+          intended for the local computer or the remote server. C-Kermit
+          8.0.200 and earlier always executes these commands on the local
+          computer. If you want them executed by the remote server, you
+          have to prefix them with REMOTE (e.g. REMOTE CD) or use special
+          R-command aliases (e.g. RCD = REMOTE CD, RDIR = REMOTE DIR,
+          etc). But this feels unnatural to FTP users, who expect
+          unprefixed file management commands to be executed by the
+          remote server, rather than locally. C-Kermit 8.0.201 adds
+          automatic locus switching to present an FTP-like interface for
+          FTP connections and the normal Kermit interface for Kermit
+          connections, and a SET LOCUS command (described below) to
+          control whether or how this is done. For when LOCUS is REMOTE,
+          a new set of commands was added for local management: LCD
+          (Local CD), LDIR (Local DIR), etc. These are described below
+          under SET LOCUS.
+
+   MORE filename
+          Equivalent to TYPE /PAGE.
+
+   ORIENTATION
+          Displays symbolic directory names and the corresponding
+          variable names and values. The symbolic names, such as exedir,
+          inidir, startup, download, and home, can be used as arguments
+          to the new KCD command.
+
+   PROMPT [ text ]
+          For use in a macro or command file: enters interactive command
+          mode within the current context ([387]Section 8.1). If the
+          optional text is included, the prompt is set to it. The text
+          can include variables, functions, etc, as in the SET PROMPT
+          command. They are evaluated each time the prompt is printed.
+          Unlike the SET PROMPT command, the text argument applies only
+          to the current command level. Thus you can have different
+          prompts at different levels.
+
+   REMOTE SET MATCH { DOTIFILE, FIFO } { ON, OFF }
+          Allows the client to tell the server whether wildcards sent to
+          the server should match dot files (files whose names begin with
+          period) or FIFOs (named pipes). See SET MATCH.
+
+   SET ATTRIBUTE RECORD-FORMAT { ON, OFF }
+          Allows control of the Kermit's Record-Format attribute. Set
+          this to OFF in case incoming file are refused due to unknown or
+          invalid record formats if you want to accept the file anyway
+          (and, perhaps, postprocess it to fix its record format).
+
+   SET CD HOME [ directory ]
+          Specifies the target directory for the CD and KCD commands,
+          when they are given without an argument, and also sets the
+          value of the \v(home) variable.
+
+   SET EXIT HANGUP { OFF, ON }
+          Normally ON, meaning that when Kermit exits, it also explicitly
+          hangs up the current SET LINE / SET PORT serial port according
+          to the current SET MODEM TYPE and SET MODEM HANGUP METHOD, and
+          closes the port device if it was opened by Kermit in the first
+          place (as opposed to inherited). SET EXIT HANGUP OFF tells
+          Kermit not to do this. This can't prevent the operating system
+          from closing the device when Kermit exits (and it's a "last
+          close") but if the port or modem have been conditioned to
+          somehow ignore the close and keep the connection open, at least
+          Kermit itself won't do anything explicit to hang it up or close
+          it.
+
+   SET FILE EOF { CTRL-Z, LENGTH }
+          Specifies the end-of-file detection method to be used by
+          C-Kermit when sending and receiving text files, and in the TYPE
+          and similar text-file oriented commands. The normal and default
+          method is LENGTH. You can specify CTRL-Z when handling CP/M or
+          MS-DOS format text files, in which a Ctrl-Z (ASCII 26)
+          character within the file marks the end of the file.
+
+   SET FILE LISTSIZE number
+          Allocates space for the given number of filenames to be filled
+          in by the wildcard expander. The current number is shown by
+          SHOW FILE. If you give a command that includes a filename
+          containing a wildcard (such as "*") that matches more files
+          that Kermit's list has room for, you can adjust the list size
+          with this command.
+
+   SET FILE STRINGSPACE number
+          Allocates space for the given amount of filename strings for
+          use by the wildcard expander. The current number is shown by
+          SHOW FILE. The number is the total number of bytes of all the
+          file specifications that match the given wildcard.
+
+     If you need to process a bigger list of files than your computer
+     has memory for, you might be able use an external file list. The
+     Kermit SEND and the FTP PUT and GET commands accept a /LISTFILE:
+     switch, which gives the name of a file that contains the list of
+     files to be transferred. Example for UNIX:
+
+  !find . -print | grep / > /tmp/names
+  ftp put /update /recursive /listfile:/tmp/names
+
+   SET LOCUS { AUTO, LOCAL, REMOTE }
+          Added in C-Kermit 8.0.201.   Sets the locus for unprefixed file
+          management commands such as CD, DIRECTORY, MKDIR, etc. When
+          LOCUS is LOCAL these commands act locally and a REMOTE (or R)
+          prefix (e.g. REMOTE CD, RCD, RDIR) is required to send file
+          management commands to a remote server. When LOCUS is REMOTE,
+          an L prefix is required to issue local file management commands
+          (e.g. LCD, LDIR). The word LOCAL can't be used as a prefix
+          since it is already used for declaring local variables. LOCUS
+          applies to all types of connections, and thus is orthogonal to
+          SET GET-PUT-REMOTE, which selects between Kermit and FTP for
+          remote file-transfer and management commands. The default LOCUS
+          is AUTO, which means we switch to REMOTE whenever an FTP
+          connection is made, and to LOCAL whenever a non-FTP connection
+          is made, and switch back accordingly whenever a connnection is
+          closed. So by default, Kermit behaves in its traditional manner
+          unless you make an FTP connection, in which case it acts like a
+          regular FTP client (but better :-)   LOCUS applies to the
+          following commands:
+
+  Unprefixed    Remote       Local        Description        
+   CD (CWD)      RCD          LCD          Change (Working) Directory
+   CDUP          RCDUP        LCDUP        CD Up
+   PWD           RPWD         LPWD         Print Working Directory
+   DIRECTORY     RDIR         LDIR         Request a directory listinga
+   DELETE        RDEL         LDEL         Delete (a) file(s)
+   RENEME        RREN         LREN         Rename a file
+   MKDIR         RMKDIR       LMKDIR       Create a directory
+   RMDIR         RRMDIR       LRMDIR       Remove a directory
+
+   SET MATCH { DOTIFILE, FIFO } { ON, OFF }
+          Whether C-Kermit filename patterns (wildcards) should match
+          filenames that start with dot (period), or (Unix only) FIFOs
+          (named pipes). The defaults are to skip dotfiles in Unix but
+          match them elsewhere, and to skip FIFOs. Applies to both
+          interactive use and to server mode, when the server receives
+          wildcards, e.g. in a GET command. Also see REMOTE SET MATCH.
+
+   SET OPTIONS DIRECTORY /DOTFILES
+          Now works for server listings too (UNIX only). Give this
+          command prior to having Kermit enter server mode, and then it
+          will show files whose names begin with dot (period) when sent a
+          REMOTE DIRECTORY command.
+
+   SET QUIET ON
+          (as well as the -q command-line option) Now applies also to:
+
+          + SET HOST connection progress messages.
+          + "Press the X or E key to cancel" file-transfer message.
+          + REMOTE CD response.
+          + REMOTE LOGIN response.
+
+   SET RECEIVE PERMISSIONS { ON, OFF }
+          Tells C-Kermit whether to set the permissions of incoming files
+          (received with Kermit protocol) from the permissions supplied
+          in the file's Attribute packet (if any). Normally ON. Also see
+          SET SEND PERMISSIONS.
+
+   SET ROOT directory
+          Like UNIX chroot, without requiring privilege. Sets the root
+          for file access, does not allow reference to or creation of
+          files outside the root, and can't be undone.
+
+   SET SEND PERMISSIONS { ON, OFF }
+          Tells C-Kermit whether to include file permissions in the
+          attributes it includes with each file when sending with Kermit
+          protocol. Also see SET RECEIVE PERMISSIONS.
+
+   SET TCP { HTTP-PROXY, SOCKS-SERVER } /USER:name /PASSWORD:text
+          These commands now allow specification of username and
+          password.
+
+   SET TERMINAL . . .
+          (See [388]Section 12.)
+
+   SET TRANSFER MESSAGE [ text ]
+          Sets an initial text message to be displayed in the
+          file-transfer display. The transfer message is automatically
+          deleted once used, so must be set each time a message a
+          desired. Any variables in the message are evaluated at the time
+          the SET command is given. If the optional text is omitted, any
+          transfer message that is currently set is removed. Synonym: SET
+          XFER MSG. SHOW TRANSFER displays it if it has been set but not
+          yet used.
+
+   SHOW COMMUNICATIONS
+          In C-Kermit 8.0, SHOW COMMUNICATIONS, when given in remote mode
+          (i.e. before any connection has been established), tells the
+          typical dialout device name for the particular platform on
+          which it's running (e.g. TXA0: for VMS, or /dev/cua0p0 for
+          HP-UX). On Unix platforms, it also tells the name of the
+          lockfile directory. This way, you have an idea of what the SET
+          LINE device name should look like, and if the SET LINE command
+          fails, you know the name of the directory or device that is
+          protected against you.
+
+   SHOW VARIABLES [ name [ name [ ... ] ] ]
+          In C-Kermit 8.0.201 you can request values of a list of
+          built-in (\v(xxx)) variables. Each name is a pattern, as
+          before, but now it a free pattern rather than an anchored one
+          (explained in [389]Section 8.12) so now "show var date time"
+          shows the values of all variables whose names include the
+          strings "date" or "time".
+
+   TAIL [ switches ] filename
+          Equivalent to TYPE /TAIL [ other-switches ] filename.
+
+   TRANSMIT /NOECHO [ other switches ] filename
+          The /NOECHO switch is equivalent to giving the command SET
+          TRANSMIT ECHO OFF prior to the TRANSMIT command, except the
+          switch affects only the command with which it was given and
+          does not affect the prevailing global setting.
+
+   TRANSMIT /NOWAIT [ other switches ] filename
+          The /NOWAIT switch is equivalent to giving the command SET
+          TRANSMIT PROMPT 0 prior to the TRANSMIT command, except the
+          switch affects only the command with which it was given and
+          does not affect the prevailing global setting.
+
+   TRANSMIT /NOWAIT /NOECHO /BINARY [ other switches ] filename
+          When the TRANSMIT command is given with the /NOWAIT, /NOECHO,
+          and /BINARY switches, this activates a special "blast the whole
+          file out the communications connection all at once" mode that
+          Kermit didn't have prior to version 8.0. There has been
+          increasing demand for this type of transmission with the advent
+          of devices that expect image (e.g. .JPG) or sound (e.g. .MP3)
+          files as raw input. The obvious question is: how does the
+          receiving device know when it has the whole file? This depends
+          on the device, of course; usually after a certain amount of
+          time elapses with nothing arriving, or else when Kermit hangs
+          up or closes the connection.
+
+   TYPE /CHARACTER-SET:name
+          Allows you to specify the character set in which the file to be
+          typed is encoded.
+
+   TYPE /NUMBER
+          Adds line numbers.
+
+   TYPE /OUTPUT:filename
+          Sends the results of the TYPE command to the given file.
+
+   TYPE /TRANSLATE-TO:name
+          Used in conjunction with TYPE /CHARACTER-SET:xxx; allows you to
+          specify the character set in which the file is to be displayed.
+
+   TYPE /TRANSPARENT
+          Used to disable character-set translation in the TYPE command,
+          which otherwise can take place automatically based on file
+          scanning, even when /CHARACTER-SET and /TRANSLATE-TO switches
+          are not given.
+
+   VOID text
+          Parses the text, evaluating any backslash items in it (such as
+          function calls) but doesn't do anything further, except
+          possibly printing error messages. Useful for invoking functions
+          that have side effects without using or printing their direct
+          results, e.g. "void \fsplit(\%a,&a)".
+
+  Symbolic Links in UNIX
+
+   The UNIX versions of C-Kermit have had /FOLLOWLINKS and /NOFOLLOWLINKS
+   switches added to several commands to control the treatment of
+   symbolic links. Different commands deal differently with symbolic
+   links:
+
+   Kermit SEND, FTP MPUT
+          /NOFOLLOWLINKS is the default, which means symbolic links are
+          skipped entirely. The alternative, /FOLLOWLINKS, should be used
+          with caution, since an innocent link might point to a whole
+          file system, or it might cause a loop. There is no way in
+          Kermit or FTP protocol to send the link itself. We either skip
+          them or follow them; we can't duplicate them.
+
+   DIRECTORY
+          /NOFOLLOWLINKS is the default, which means the DIRECTORY
+          command lists symbolic links in a way that shows they are
+          links, but it does not follow them. The alternative,
+          /FOLLOWLINKS, follows links and gives information about the
+          linked-to directories and files.
+
+   DELETE, RMDIR
+          The DELETE command does not have link-specific switches. DELETE
+          never follows links. If you tell Kermit to delete a symbolic
+          link, it deletes the link itself, not the linked-to file. Ditto
+          for RMDIR.
+
+   COPY
+          The COPY command behaves just like the UNIX cp command; it
+          always follows links.
+
+   RENAME
+          The RENAME command behaves just like the UNIX mv command; it
+          operates on links directly rather than following.
+
+   [ [390]Top ] [ [391]Contents ] [ [392]C-Kermit Home ] [ [393]Kermit
+   Home ]
+  __________________________________________________________________________
+
+8. OTHER SCRIPTING IMPROVEMENTS
+
+  8.1. Performance and Debugging
+
+   A command cache for frequently used commands plus some related
+   optimizations increases the speed of compute-bound scripts by anywhere
+   from 50% to 1000%.
+
+   The new PROMPT command can be used to set breakpoints for debugging
+   scripts. If executed in a command file or macro, it gives you an
+   interactive command prompt in the current context of the script, with
+   all its variables, arguments, command stack, etc, available for
+   examination or change, and the ability to resume the script at any
+   point (END resumes it, Ctrl-C or STOP cancels it and returns to top
+   level).
+
+   The new Ctrl-C trapping feature ([394]Section 8.14) lets you intercept
+   interruption of scripts. This can be used in combination with the
+   PROMPT command to debug scripts. Example:
+
+define ON_CTRLC {
+    echo INTERRUPTED BY CTRL-C...
+    echo The command stack has not yet been rolled back:
+    show stack
+    echo Type Ctrl-C again or use the END command to return to top level.
+    prompt Debug>
+}
+
+   Adding this ON_CTRL definition to your script lets you interrupt it at
+   any point and get prompt that is issued at the current command level,
+   so you can query local variables, etc.
+
+   [ [395]Top ] [ [396]Contents ] [ [397]C-Kermit Home ] [ [398]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.2. Using Macros as Numeric Variables
+
+   A macro is a way to assign a value to a name, and then use the name to
+   refer to the value. Macros are used in two ways in Kermit: as
+   "subroutines" or functions composed of Kermit commands, which are
+   executed, or as variables to hold arbitrary values -- text, numbers,
+   filenames, etc.
+
+   When a macro is to be executed, its name is given as if it were a
+   C-Kermit command, optionally preceded by the word "do". When a macro
+   is used as a variable, it must be "escaped" with \m(xxx) (or
+   equivalent function, e.g. \s(xxx), \:(xxx), \fdefinition(xxx)), where
+   xxx is the macro name, for example:
+
+  define filename /usr/olga/oofa.txt
+  send \m(filename)
+
+   Of course variables can also hold numbers:
+
+  define size 17
+  declare \&a[\m(size)]
+  ...
+  define index 3
+  if ( == \m(index) 3 ) echo The third value is: \&a[\m(index)]
+  evaluate index (\m(index) * 4)
+  if ( > \m(index) \m(size) ) echo Out of range!
+
+   But these are contexts in which only numbers are valid. C-Kermit 8.0
+   has been changed to treat non-escaped non-numeric items in strictly
+   numeric contexts as macro names. So it is now possible (but not
+   required) to omit the \m(...) notation and just use the macro name in
+   these contexts:
+
+  define size 17
+  declare \&a[size]
+  ...
+  define index 3
+  if ( == index 3 ) echo The third value is: \&a[index]
+  evaluate index (index * 4)
+  if ( > index size ) echo Out of range!
+
+   This is especially nice for loops that deal with arrays. Here, for
+   example, is a loop that reverses the order of the elements in an
+   array. Whereas formerly it was necessary to write:
+
+  .\%n ::= \fdim(&a)
+  for \%i 1 \%n/2 1 {
+      .tmp := \&a[\%n-\%i+1]
+      .\&a[\%n-\%i+1] := \&a[\%i]
+      .\&a[\%i] := \m(tmp)
+  }
+
+   Recoding this to use macro names "i" and "n" instead of the backslash
+   variables \%i and \%n, we have:
+
+  .n ::= \fdim(&a)
+  for i 1 n/2 1 {
+      .tmp := \&a[n-i+1]
+      .\&a[n-i+1] := \&a[i]
+      .\&a[i] := \m(tmp)
+  }
+
+   which reduces the backslash count to less than half. The final
+   statement in the loop could be written ".\&a[i] ::= tmp" if the array
+   contained only numbers (since ::= indicates arithmetic expression
+   evaluation).
+
+   Also, now you can use floating-point numbers in integer contexts (such
+   as array subscripts), in which case they are truncated to an integer
+   value (i.e. the fractional part is discarded).
+
+   Examples of numeric contexts include:
+
+     * Array subscripts.
+     * Any numeric function argument.
+     * Right-hand side of ::= assignments.
+     * EVALUATE command or \fevaluate() function expression.
+     * The INCREMENT or DECREMENT by-value.
+     * IF =, >, <, !=, >=, and <= comparands.
+     * The IF number construct.
+     * FOR-loop variables.
+     * STOP, END, and EXIT status codes.
+     * The INPUT timeout value.
+     * PAUSE, WAIT, SLEEP, MSLEEP intervals.
+     * The SHIFT argument.
+     * Numeric switch arguments, e.g. TYPE /WIDTH:number, SEND
+       /LARGER:number.
+     * SCREEN MOVE-TO row and column number.
+     * Various SET DIAL parameters (timeout, retry limit, etc).
+     * Various SET SEND or RECEIVE parameters (packet length, window
+       size, etc).
+     * Various other SET parameters.
+
+   and:
+
+     * S-Expressions (explained in [399]Section 9).
+
+   Macro names used in numeric contexts must not include mathematical
+   operators. Although it is legal to create a macro called "foo+bar", in
+   a numeric context this would be taken as the sum of the values of
+   "foo" and "bar". Any such conflict can be avoided, of course, by
+   enclosing the macro name in \m(...).
+
+   [ [400]Top ] [ [401]Contents ] [ [402]C-Kermit Home ] [ [403]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.3. New IF Conditions
+
+   Several new IF conditions are available:
+
+   IF DECLARED arrayname
+          Explained in [404]Section 8.6.
+
+   IF KBHIT
+          Allows a script to test whether a key was pressed without
+          actually trying to read it.
+
+   IF KERBANG (Unix only)
+          True if Kermit was started from a Kerbang script. This is
+          useful for knowing how to interpret the \&@[] and \&_[]
+          argument vector arrays, and under what conditions to exit.
+
+   IF INTEGER n
+          This is just a synonym for IF NUMERIC, which is true if n
+          contains only digits (or, if n is a variable, its value
+          contains only digits).
+
+   By contrast, IF FLOAT n succeeds if n is a floating-point number OR an
+   integer (or a variable with floating-point or integer value).
+   Therefore, IF FLOAT should be used whenever any kind of number is
+   acceptable, whereas IF INTEGER (or IF NUMERIC) when only an integer
+   can be used.
+
+   [ [405]Top ] [ [406]Contents ] [ [407]C-Kermit Home ] [ [408]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.4. The ON_UNKNOWN_COMMAND Macro
+
+   The new ON_UNKNOWN_COMMAND macro, if defined, is executed whenever you
+   give a command that is not known to C-Kermit; any operands are passed
+   as arguments. Here are some sample definitions:
+
+  DEF ON_UNKNOWN_COMMAND telnet \%1 ; Treat unknown commands as hostnames
+  DEF ON_UNKNOWN_COMMAND dial \%1   ; Treat unknown commands phone numbers
+  DEF ON_UNKNOWN_COMMAND take \%1   ; Treat unknown commands as filenames
+  DEF ON_UNKNOWN_COMMAND !\%*       ; Treat unknown commands as shell commands
+
+   The ON_CD macro, if defined, is executed whenever Kermit is given a CD
+   (change directory) command (8.0.211). Upon entry to this macro, the
+   directory has already changed and the new directory string is
+   available in the \v(directory) variable, and also as the first
+   argument (\%1).
+
+   [ [409]Top ] [ [410]Contents ] [ [411]C-Kermit Home ] [ [412]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.5. The SHOW MACRO Command
+
+   The SHOW MACRO command has been changed to accept more than one macro
+   name:
+
+  (setq a 1 b 2 c 3)
+  show mac a b c
+  a = 1
+  b = 2
+  c = 3
+
+   An exact match is required for each name (except that case doesn't
+   matter). If you include wildcard characters, however, a pattern match
+   is performed:
+
+  show mac [a-c]*x
+
+   shows all macros whose names start with a, b, or c, and end with x.
+
+   [ [413]Top ] [ [414]Contents ] [ [415]C-Kermit Home ] [ [416]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.6. Arrays
+
+   A clarification regarding references to array names (as opposed to
+   array elements): You can use array-name "abbreviations" like &a only
+   in contexts that expect array names, like ARRAY commands or array-name
+   function arguments such as the second argument of \fsplit(). In a
+   LOCAL statement, however, you have to write \&a[], since "local &a"
+   might refer to a macro named "&a".
+
+   In function arguments, however, you MUST use the abbreviated form:
+   \fsplit(\%a,&a) or \fsplit(\%a,&a[]). If you include the backslash (as
+   in "\fsplit(\%a,\&a[])") a parse error occurs.
+
+   Here are the new array-related commands:
+
+   IF DECLARED arrayname
+          Allows a script to test whether an array has been declared. The
+          arrayname can be a non-array backslash variable such as \%1 or
+          \m(name), in which case it is evaluated first, and the result
+          is treated as the array name. Otherwise, arrayname is treated
+          as in the ARRAY commands: it can be a, &a, &a[], \&a, \&a[],
+          \&a[3], \&a[3:9], etc, with the appropriate results in each
+          case. Synonym: IF DCL.
+
+   UNDECLARE arrayname
+          UNDECLARE is a new top-level command to undeclare an array.
+          Previously this could only be done with "declare \&a[0]" (i.e.
+          re-declare the array with a dimension of 0).
+
+   ARRAY LINK linkname arrayname
+          Creates a symbolic link from the array named by linkname (which
+          must be the name of an array that is not yet declared in the
+          current context) to the array named by arrayname (which must
+          the name of a currently declared array that is not itself a
+          link, or a variable containing the name of such an array). The
+          two names indicate the same array: if you change an array
+          element, the change is reflected in the link too, and vice
+          versa. If you undeclare the link, the real array is unaffected.
+          If you undeclare the real array, all links to it disappear. If
+          you resize an array (directly or through a link), all links to
+          it are updated automatically.
+
+   Array links let you pass array names as arguments to macros. For
+   example, suppose you had a program that needed to uppercase all the
+   elements of different arrays at different times. You could write a
+   macro to do this, with the array name as an argument. But without
+   array links, there would be no way to refer to the argument array
+   within the macro. Array links make it easy:
+
+  define arrayupper {
+      local \&e[] \%i
+      array link \&e[] \%1
+      for i 1 \fdim(&e) 1 { .\&e[i] := \fupper(\&e[i]) }
+  }
+  declare \&a[] = these are some words
+  arrayupper &a
+  show array &a
+
+   The macro declares the array link LOCAL, which means it doesn't
+   conflict with any array of the same name that might exist outside the
+   macro, and that the link is destroyed automatically when the macro
+   exits. This works, by the way, even if the link name and the macro
+   argument name are the same, as long as the link is declared LOCAL.
+
+   As noted, you can't make a link to a nonexistent array. So when
+   writing a macro whose job is to create an array whose name is passed
+   as an argument, you must declare the array first (the size doesn't
+   matter as long as it's greater than 0). Example:
+
+  define tryme {                ; Demonstration macro
+      local \&e[]               ; We only need this inside the macro
+      array link \&e[] \%1      ; Make local link
+      shift                     ; Shift argument list
+      void \fsplit(\%*,&e)      ; Split remainder of arg list into array
+  }
+  declare \&a[1]                ; Declare target array in advance
+  tryme &a here are some words  ; Invoke the macro with array name and words
+  show array a                  ; See the results
+
+   One final improvement allows the macro itself to declare the array
+   (this was not possible in earlier Kermit releases): if the array name
+   in the DECLARE command is a variable (and not an array name), or
+   includes variables, the resulting value is used as the array name. So:
+
+  define tryme {                ; Demonstration macro
+      declare \%1[1]            ; Preliminary declaration for target array
+      local \&e[]               ; We only need this inside the macro
+      array link \&e[] \%1      ; Make local link
+      shift                     ; Shift argument list
+      void \fsplit(\%*,&e)      ; Split remainder of arg list into array
+  }
+  tryme &a here are some words  ; Invoke the macro with array name and words
+  show array a                  ; See the results
+
+   The SHOW ARRAY command now indicates whether an array name is a link.
+
+   Also see the descriptions of [417]\fjoin() and [418]\fsplit(), plus
+   [419]Section 8.10 on the MINPUT command, which shows how an entire
+   array (or segment of it) can be used as the MINPUT target list.
+
+   [ [420]Top ] [ [421]Contents ] [ [422]C-Kermit Home ] [ [423]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.7. New or Improved Built-in Variables and Functions
+
+   The following new built-in variables are available:
+
+  \v(buildid)       A date string like "20000808" indicating when C-Kermit was
+built.
+  \v(ftime)         Current time, secs since midnight, including fraction of se
+cond.
+  \v(iprompt)       The current SET PROMPT value
+  \v(sexp)          The most recent S-Expression (see [424]Section 9)
+  \v(sdepth)        The current S-Expression invocation depth ([425]Section 9)
+  \v(svalue)        The value of the most recent S-Expression ([426]Section 9)
+
+  \v(ftp_code)      Most recent FTP response code ([427]Section 3)
+  \v(ftp_connected) FTP connection status ([428]Section 3)
+  \v(ftp_cpl)       FTP Command Protection Level ([429]Section 3.2)
+  \v(ftp_dpl)       FTP Data Protection Level ([430]Section 3.2)
+  \v(ftp_getputremote) The current SET GET-PUT-REMOTE setting ([431]Section 3.8
+)
+  \v(ftp_host)      Name or IP address of FTP server ([432]Section 3)
+  \v(ftp_loggedin)  FTP login status ([433]Section 3)
+  \v(ftp_message)   Most recent FTP response message ([434]Section 3)
+  \v(ftp_security)  FTP Security method ([435]Section 3.2)
+  \v(ftp_server)    OS type of FTP server ([436]Section 3)
+
+  \v(http_code)       Most recent HTTP response code
+  \v(http_connected)  HTTP connection status
+  \v(http_host)       Name or IP address of HTTP server
+  \v(http_message)    Most recent HTTP response message
+  \v(http_security)   TLS cipher used to secure the HTTP session
+
+  \v(hour)            Hour of the day, 0 to 23.
+  \v(timestamp)       Equivalent to "\v(ndate) \v(time)".
+
+  \v(log_debug)       Current debug log file, if any.
+  \v(log_packet)      Current packet log file, if any.
+  \v(log_session)     Current session log file, if any.
+  \v(log_transaction) Current transaction log file, if any.
+  \v(log_connection)  Current connection log file, if any.
+
+   The following new or improved built-in functions are available:
+
+  \fcmdstack()            Allows programmatic access to the command stack.
+  \fcvtdate()             [437]Section 8.13, format options added
+  \fdelta2secs()          [438]Section 8.13
+  \fdostounixpath(s1)     Converts a DOS filename to Unix format.
+  \fsplit()               Now allows grouping/nesting in source string.
+  \fword()                Allows the same grouping and nesting.
+  \fjoin(&a,s1,n1,n2)     Copies an array into a single string.
+  \fsubstitute(s1,s2,s3)  Substitutes characters within a string.
+  \freplace()             Has new 4th "occurrence" argument.
+  \fsexpression()         Evaluates an S-Expression (explained in [439]Section
+9).
+  \ftrim(), \fltrim()     Now trim CR and LF by default, as well as SP and Tab.
+  \funixtodospath(s1)     Converts a Unix filename to DOS format.
+  \fkeywordval(s1,c1)     Assigns values to keywords (macros) (explained below)
+.
+
+   Most functions that have "2" in their names to stand for the word "to"
+   can now also be written with "to", e.g. "\fdelta2secs(),"
+   \fdeltatosecs()."
+
+   \funtabify(string)
+          (New to 8.0.211) Replaces Horizontal Tab characters in the
+          given string with spaces based on VT100-like tab stops.
+
+   \fverify(s1,s2,n)
+          As of version 8.0.211, returns -1 if s2 is an empty string.
+          Previously it returned 0, making \fverify(abc,\%a) look as if
+          \%a was a string combosed of a's, b's, and/or c's when in fact
+          it contained nothing.
+
+   \fcode(string)
+          As of version 8.0.211, returns 0 if string is empty or missing.
+          Previously it returned the empty string, which made it unsafe
+          to use in arithmetic or boolean expressions.
+
+   \v(inscale)
+          New to version 8.0.211, its value is the INPUT SCALE-FACTOR
+          ([440]Section 8.10), default 1.0.
+
+  8.7.1. The \fkeywordval() Function
+
+   \fkeywordval(s1,c1) is new to C-Kermit 8.0. Given a string s1 of the
+   form "name=value", it creates a macro with the given name and assigns
+   it the given value. If no value appears after the equal sign, any
+   existing macro of the given name is undefined. Blanks are
+   automatically trimmed from around the name and value. The optional c1
+   parameter is the assignment operator character, equal sign (=) by
+   default. This function is handy for processing keyword parameters or
+   any other form of parameter-value pair. Suppose, for example, you want
+   to write a macro that accepts keyword parameters rather than
+   positional ones:
+
+  define MYDIAL {
+      local \%i modem hangup method device speed number
+      def number 5551234          ; Assign default parameter values
+      def speed 57600
+      def modem usrobotics
+      def hangup rs232
+      def method tone
+      def country 1
+      for \%i 1 \v(argc)-1 1 {    ; Parse any keyword parameters...
+          if not \fkeywordval(\&_[\%i]) end 1 Bad parameter: "\&_[\%i]"
+      }
+      set dial country \m(country)
+      set modem type \m(modem)
+      set modem hang \m(hangup)
+      set dial method \m(tone)
+      set line \m(device)
+      if fail stop 1
+      set speed \m(speed)
+      if fail stop 1
+      show comm
+      set dial display on
+      dial \m(number)
+      if success connect
+  }
+
+   In this example, all the defaults are set up inside the macro, and
+   therefore it can be invoked with no parameters at all. But if you want
+   to have the macro dial a different number, you can supply it as
+   follows:
+
+  mydial number=7654321
+
+   You can supply any number of keyword parameters, and you can give them
+   in any order:
+
+  mydial number=7654321 hangup=modem speed=115200
+
+  8.7.2. The \fsplit(), \fjoin(), and \fword() Functions
+
+   \fjoin(&a,s1,n1,n2) is also new; it creates a string from an array (or
+   a piece of one). &a is the name of the array (a range specifier can be
+   included); s1 is a character or string to separate each element in the
+   result string (can be omitted, in which case the elements are not
+   separated at all), and n1 is a grouping mask, explained below. If s1
+   is empty or not specified, the array elements are separated with
+   spaces. If you want the elements concatenated with no separator,
+   include a nonzero n2 argument. Given the array:
+
+  declare \&a[] = 0 1 2 3 4 5 6 7 8 9
+
+   you can get effects like this:
+
+  \fjoin(&a)      0 1 2 3 4 5 6 7 8 9
+  \fjoin(&a,:)    0:1:2:3:4:5:6:7:8:9
+  \fjoin(&a,{,})  0,1,2,3,4,5,6,7,8,9
+  \fjoin(&a,...)  0...1...2...3...4...5...6...7...8...9
+  \fjoin(&a,,,1)  0123456789
+
+   \fsplit(), \fword(), \fstripb(), and \fjoin() accept a "grouping mask"
+   argument, n1, which is a number from 0 to 63, in which:
+
+   1 = "" doublequotes
+   2 = {} braces
+   4 = '' singlequotes
+   8 = () parentheses
+  16 = [] square brackets
+  32 = <> angle brackets
+
+   These can be OR'd (added) together to make any number 0-63 (-1 is
+   treated the same as 63, 0 means no grouping). If a bit is on, the
+   corresponding kind of grouping is selected. (If more than 1 bit is set
+   for \fjoin(), only the lowest-order one is used.)
+
+   If you include the same character in the grouping mask and the include
+   list, the grouping mask takes precedence. Example:
+
+  def \%a  a "b c d" e
+  \fsplit(\%a,&a[],,,-1)  = 3  <-- doublequote used for grouping
+  \fsplit(\%a,&a[],,",-1) = 3  <-- doublequote still used for grouping
+
+   Nesting of matched left and right grouping characters (parentheses,
+   braces, and brackets, but not quotes) is recognized. Example:
+
+  def \%a a (b c <d e [f g {h i} j k] l m> n o) p
+  \fsplit(\%a,&a,,,0)  = 16 (no grouping)
+  \fsplit(\%a,&a,,,2)  = 15 (braces only)
+  \fsplit(\%a,&a,,,16) = 11 (square brackets only)
+  \fsplit(\%a,&a,,,32) =  7 (angle brackets only)
+  \fsplit(\%a,&a,,,63) =  3 (all)
+  \fsplit(\%a,&a,,,-1) =  3 (all)
+
+   \fsplit() and \fjoin() are "reciprocal" functions. You can split a
+   string up into an array and join it back into a new string that is
+   equivalent, as long as \fsplit() and \fjoin() are given equivalent
+   grouping masks, except that the type of braces might change. Example:
+
+  def \%a a {b c [d e] f g} "h i" j <k l> m
+  echo STRING=[\%a]
+  echo WORDS=\fsplit(\%a,&a,,,-1)
+  show array a
+  asg \%b \fjoin(&a,{ },2)
+  echo JOIN  =[\%b]
+  echo WORDS=\fsplit(\%b,&b,,,-1)
+  show array b
+
+   The arrays a and b are identical. The strings a and b are as follows:
+
+  \%a: a {b c [d e] f g} "h i" j <k l> m
+  \%b: a {b c [d e] f g} {h i} j {k l} m
+
+   It is possible to quote separator grouping characters with backslash
+   to override their grouping function. And of course to include
+   backslash itself in the string, it must be quoted too. Furthermore,
+   each backslash must be doubled, so the command parser will still pass
+   one backslash to \fsplit() for each two that it sees. Here are some
+   examples using \fsplit() with a grouping mask of 8 (treat parentheses
+   as grouping characters).
+
+  String                  Result
+    a b c d e f             6
+    a b\\ c d e f           5
+    a b (c d e) f           4
+    a b \\(c d e\\) f       6
+    a b \\\\(c d e\\\\) f   7
+
+   \fsplit() has also been changed to create its array (if one is given)
+   each time it is called, so now it can be conveniently called in a loop
+   without having to redeclare the array each time.
+
+   Incidentally... Sometimes you might want to invoke \fsplit() in a
+   situation where you don't care about its return value, e.g. when you
+   just want to fill the array. Now you can "call" \fsplit() or any other
+   function with the new [441]VOID command:
+
+  void \fsplit(\%a,&a)
+
+   \fsplit() and \fjoin() also accept a new, optional 6th argument, an
+   options flag, a number that can specify a number of options. So far
+   there is just one option, whose value is 1:
+
+   separator-flag
+          Normally separators are collapsed. So, for example,
+
+  \fword(Three        little          words,2)
+
+          returns "little" (the second word). Space is a separator, but
+          there are multiple spaces between each word. If the value 1 is
+          included in the option flag, however, each separator counts. If
+          two separators are adjacent, an empty word is produced between
+          them. This is useful for parsing (e.g.) comma-separated lists
+          exported from databases or spreadsheets.
+
+  8.7.3. The \fcmdstack() Function
+
+   The new \fcmdstack() function gives access to the command stack:
+
+   \fcmdstack(n1,n2)
+          Arguments: n1 is the command stack level. If omitted, the
+          current level, \v(cmdlevel), is used. n2 is a function code
+          specifying the desired type of information:
+
+  0 (default) = name of object at level n1.
+  1 (nonzero) = object type (0 = prompt; 1 = command file; 2 = macro).
+
+          The default for n2 is 0.
+
+   The name associated with prompt is "(prompt)". Here's a loop that can
+   be included in a macro or command file to show the stack (similar to
+   what the SHOW STACK command does):
+
+  for \%i \v(cmdlevel) 0 -1 {
+      echo \%i. [\fcmdstack(\%i,1)] \fcmdstack(\%i,0)
+  }
+
+   In this connection, note that \v(cmdfile) always indicates the most
+   recently invoked active command file (if any), even if that file is
+   executing a macro. Similarly, \v(macro) indicates the most recently
+   invoked macro (if any), even if the current command source is not a
+   macro. The name of the "caller" of the currently executing object
+   (command file or macro) is:
+
+  \fcmdstack(\v(cmdlevel)-1)
+
+   and its type is:
+
+  \fcmdstack(\v(cmdlevel)-1,1)
+
+   To find the name of the macro that invoked the currently executing
+   object, even if one or more intermediate command files (or prompting
+   levels) are involved, use a loop like this:
+
+  for \%i \v(cmdlevel)-1 0 -1 {
+      if = \fcmdstack(\%i,1) 2 echo CALLER = \fcmdstack(\%i,0)
+  }
+
+   Of course if you make a macro to do this, the macro must account for
+   its own additional level:
+
+  define CALLER {
+      for \%i \v(cmdlevel)-2 0 -1 {
+          if = \fcmdstack(\%i,1) 2 return \fcmdstack(\%i,0)
+      }
+      return "(none)"
+  }
+
+   The built-in variable \v(cmdsource) gives the current command source
+   as a word ("prompt", "file", or "macro").
+
+  8.7.4. The VOID Command
+
+   VOID is like ECHO in that all functions and variables in its argument
+   text are evaluated. but it doesn't print anything (except possibly an
+   error message if a function was invocation contained or resulted in
+   any errors). VOID sets FAILURE if it encounters any errors, SUCCESS
+   otherwise.
+
+   [ [442]Top ] [ [443]Contents ] [ [444]C-Kermit Home ] [ [445]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.8. The RETURN and END Commands
+
+   The execution of a macro is terminated in any of the following ways:
+
+     * With an END [ number [ message ] ] command. If a number is given,
+       the macro succeeds if the number is 0, and fails if it is not
+       zero; if a number is not given, the macro succeeds.
+     * With a STOP command, which works just like END except it peels
+       back the command stack all the way to top level.
+     * With a RETURN [ text ] command, in which case the macro always
+       succeeds.
+     * By running out of commands to execute, in which case the macro
+       succeeds or fails according the most recently executed command
+       that sets success or failure.
+
+   The same considerations apply to command files invoked by the TAKE
+   command.
+
+   If a macro does not execute any commands that set success or failure,
+   then invoking the macro does not change the current SUCCESS/FAILURE
+   status. It follows, then, that the mere invocation of a macro does not
+   change the SUCCESS/FAILURE status either. This makes it possible to
+   write macros to react to the status of other commands (or macros), for
+   example:
+
+  define CHKLINE {
+      if success end 0
+      stop 1 SET LINE failed - please try another device.
+  }
+  set modem type usrobotics
+  set line /dev/cua0
+  chkline
+  set speed 57600
+  dial 7654321
+
+   By the way, none of this is news. But it was not explicitly documented
+   before, and C-Kermit 7.0 and earlier did not always handle the RETURN
+   statement as it should have.
+
+   [ [446]Top ] [ [447]Contents ] [ [448]C-Kermit Home ] [ [449]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.9. UNDEFINing Groups of Variables
+
+   The UNDEFINE command, which previously accepted one variable name, now
+   accepts a list of them, and also accepts wildcard notation to allow
+   deletion of variables that match a given pattern.
+
+   UNDEFINE [ switches ] name [ name [ name [ ... ] ] ]
+          Undefines the variables whose names are given. Up to 64 names
+          may be given in one UNDEFINE command.
+
+   If you omit the switches and include only one name, the UNDEFINE
+   command works as before.
+
+   Switches include:
+
+   /MATCHING
+          Specifies that the names given are to treated as patterns
+          rather than literal variable names. Note: pattern matching
+          can't be used with array references; use the ARRAY command to
+          manipulate arrays and subarrays.
+
+   /LIST
+          List the name of each variable to be undefined, and whether it
+          was undefined successfully ("ok" or "error"), plus a summary
+          count at the end.
+
+   /SIMULATE
+          List the names of the variables that would be deleted without
+          actually deleting them. Implies /LIST.
+
+   The UNDEFINE command fails if there were any errors and succeeds
+   otherwise.
+
+   The new _UNDEFINE command is like UNDEFINE, except the names are
+   assumed to be variable names themselves, which contain the names (or
+   parts of them) of the variables to be undefined. For example, if you
+   have the following definitions:
+
+  define \%a foo
+  define foo This is some text
+
+   then:
+
+  undef \%a
+
+   undefines the variable \%a, but:
+
+  _undef \%a
+
+   undefines the macro foo.
+
+   Normal Kermit patterns are used for matching; metacharacters include
+   asterisk, question mark, braces, and square brackets. Thus, when using
+   the /MATCHING switch, if the names of the macros you want to undefine
+   contain any of these characters, you must quote them with backslash to
+   force them to be taken literally. Also note that \%* is not the name
+   of a variable; it is a special notation used within a macro for "all
+   my arguments". The command "undef /match \%*" deletes all \%x
+   variables, where x is 0..9 and a..z. Use "undef /match \%[0-9]" to
+   delete macro argument variables or "undef /match \%[i-n]" to delete a
+   range of \%x variables.
+
+   [ [450]Top ] [ [451]Contents ] [ [452]C-Kermit Home ] [ [453]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.10. The INPUT and MINPUT Commands
+
+   As of C-Kermit 8.0.211, the INPUT and MINPUT commands accept a switch:
+
+   [M]INPUT /NOMATCH timeout
+          The /NOMATCH switch allows INPUT or MINPUT to read incoming
+          material for the specified amount of time, without attempting
+          to match it with any text or patterns. When this switch is
+          included, the [M]INPUT command succeeds when the timeout
+          interval expires, with \v(instatus) set to 1, meaning "timed
+          out", or fails upon interruption or i/o error.
+
+   Also in version 8.0.211, there is a new way to apply a scale factor to
+   [M]INPUT timeouts:
+
+   SET INPUT SCALE-FACTOR floating-point-number
+          This scales all [M]INPUT timeouts by the given factor, allowing
+          time-sensitive scripts to be adjusted to changing conditions
+          such as congested networks or different-speed modems without
+          having to change each INPUT-class command. This affects only
+          those timeouts that are given in seconds, not as wall-clock
+          times. Although the scale factor can have a fractional part,
+          the INPUT timeout is still an integer. The new built-in
+          variable \v(inscale) tells the current INPUT SCALE-FACTOR.
+
+   The MINPUT command can be used to search the incoming data stream for
+   several targets simultaneously. For example:
+
+  MINPUT 8 one two three
+
+   waits up to 8 seconds for one of the words "one", "two", or "three" to
+   arrive. Words can be grouped to indicate targets that contain spaces:
+
+  MINPUT 8 nineteeen twenty "twenty one"
+
+   And of course you can also use variables in place of (or as part of)
+   the target names:
+
+  MINPUT 8 \%a \&x[3] \m(foo)
+
+   Until now you had to know the number of targets in advance when
+   writing the MINPUT statement. Each of the examples above has exactly
+   three targets.
+
+   But suppose your script needs to look for a variable number of
+   targets. For this you can use arrays and \fjoin(), described in
+   [454]Section 8.7. Any number of \fjoin() invocations can be included
+   in the MINPUT target list, and each one is expanded into the
+   appropriate number of separate targets each time the MINPUT command is
+   executed. Example:
+
+  declare \&a[10] = one two three
+  minput 10 foo \fjoin(&a) bar
+
+   This declares an array of ten elements, and assigns values to the
+   first three of them. The MINPUT command looks for these three (as well
+   as the words "foo" and "bar"). Later, if you assign additional
+   elements to the array, the same MINPUT command also looks for the new
+   elements.
+
+   If an array element contains spaces, each word becomes a separate
+   target. To create one target per array element, use \fjoin()'s
+   grouping feature:
+
+  dcl \&a[] = {aaa bbb} {ccc ddd} {xxx yyy zzz}
+
+  minput 10 \fjoin(&a)     <-- 7 targets
+  minput 10 \fjoin(&a,,2)  <-- 3 targets
+
+   [ [455]Top ] [ [456]Contents ] [ [457]C-Kermit Home ] [ [458]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.11. Learned Scripts
+
+   C-Kermit now includes a simple script recorder that monitors your
+   commands, plus your actions during CONNECT mode, and automatically
+   generates a script program that mimics what it observed. You should
+   think of this feature as a script-writing ASSISTANT since, as you will
+   see [459]later in this section, the result generally needs some
+   editing to make it both secure and flexible. The script recorder is
+   controlled by the new LEARN command:
+
+   LEARN [ /ON /OFF /CLOSE ] [ filename ]
+          If you give a filename, the file is opened for subsequent
+          recording. The /ON switch enables recording to the current file
+          (if any); /OFF disables recording. /CLOSE closes the current
+          script recording file (if any). If you give a filename without
+          any switches, /ON is assumed.
+
+   The /OFF and /ON switches let you turn recording off and on during a
+   session without closing the file.
+
+   When recording:
+
+     * All commands that you type (or recall) at the prompt are recorded
+       in the file except:
+          + LEARN commands are not recorded.
+          + The CONNECT command is not recorded.
+          + The TELNET command is converted to SET HOST /NETWORK:TCP.
+     * Commands obtained from macros or command files are not recorded.
+     * During CONNECT:
+          + Every line you type is converted to an OUTPUT command.
+          + The last prompt before any line you type becomes an INPUT
+            command.
+          + Timeouts are calculated automatically for each INPUT command.
+          + A PAUSE command is inserted before each OUTPUT command just
+            to be safe.
+
+   Thus the script recorder is inherently line-oriented. It can't be used
+   to script character-oriented interactions like typing Space to a
+   "More?" prompt or editing a text file with VI or EMACS.
+
+   But it has advantages too; for example it takes control characters
+   into account that might not be visible to you otherwise, and it
+   automatically converts control characters in both the input and output
+   streams to the appropriate notation. It can tell, for example that the
+   "$ " prompt on the left margin in UNIX is really {\{13}\{10}$ },
+   whereas in VMS it might be {\{13}\{10}\{13}$ }. These sequences are
+   detected and recorded automatically.
+
+   A learned script should execute correctly when you give a TAKE command
+   for it. However, it is usually appropriate to edit the script a bit.
+   The most important change would be to remove any passwords from it.
+   For example, if the script contains:
+
+  INPUT 9 {\{13}\{10}Password: }
+  IF FAIL STOP 1 INPUT timeout
+  PAUSE 1
+  OUTPUT bigsecret\{13}
+
+   you should replace this by something like:
+
+  INPUT 9 {\{13}\{10}Password: }
+  IF FAIL STOP 1 INPUT timeout
+  ASKQ pswd Please type your password:
+  PAUSE 1
+  OUTPUT \m(pswd)\{13}
+
+   The LEARN command can't do this for you since it knows nothing about
+   "content"; it only knows about lines and can't be expected to parse or
+   understand them -- after all, the Password prompt might be in some
+   other language. So remember: if you use the LEARN command to record a
+   login script, be sure edit the resulting file to remove any passwords.
+   Also be sure to delete any backup copies your editor or OS might have
+   made of the file.
+
+   Other manual adjustments might also be appropriate:
+
+     * If the target of an INPUT command can vary, you can replace the
+       INPUT command with MINPUT and the appropriate target list, and/or
+       the target with a \fpattern(). For example, suppose you are
+       dialing a number that can be answered by any one of 100 terminal
+       servers, whose prompts are ts-00>, ts-01>, ts-02>, ... ts-99>. The
+       script records a particular one of these, but you want it to work
+       for all of them, so change (e.g.):
+  INPUT 10 ts-23>  ; or whatever
+       to:
+  INPUT 10 \fpattern(ts-[0-9][0-9]>)
+     * The INPUT timeout values are conservative, but they are based only
+       on a single observation; you might need to tune them.
+     * The PAUSE commands might not be necessary, or the PAUSE interval
+       might need adjustment.
+     * In case you made typographical errors during recording, they are
+       incorporated in your script; you can edit them out if you want to.
+
+   Here is a sample script generated by Kermit ("learn vms.ksc") in which
+   a Telnet connection is made to a VMS computer, the user logs in,
+   starts Kermit on VMS, sends it a file, and then logs out:
+
+  ; Scriptfile: vms.ksc
+  ; Directory:  /usr/olga
+  ; Recorded:   20001124 15:21:23
+
+  SET HOST /NETWORK:TCP vms.xyzcorp.com
+  IF FAIL STOP 1 Connection failed
+
+  INPUT 7 {\{13}\{10}\{13}Username: }
+  IF FAIL STOP 1 INPUT timeout
+  PAUSE 1
+  OUTPUT olga\{13}
+  INPUT 3 {\{13}\{10}\{13}Password: }
+  IF FAIL STOP 1 INPUT timeout
+  PAUSE 1
+  OUTPUT secret\{13}
+  INPUT 18 {\{13}\{10}\{13}$ }
+  IF FAIL STOP 1 INPUT timeout
+  PAUSE 1
+  OUTPUT set default [.incoming]\{13}
+  INPUT 12 {\{13}\{10}\{13}$ }
+  IF FAIL STOP 1 INPUT timeout
+  PAUSE 1
+  OUTPUT kermit\{13}
+  INPUT 15 {\{13}\{10}\{13}ALTO:[OLGA.INCOMING] C-Kermit>}
+  IF FAIL STOP 1 INPUT timeout
+  PAUSE 1
+  OUTPUT receive\{13}
+  send myfile.txt
+
+  INPUT 18 {\{13}\{10}\{13}ALTO:[OLGA.INCOMING] C-Kermit>}
+  IF FAIL STOP 1 INPUT timeout
+  PAUSE 1
+  OUTPUT exit\{13}
+  INPUT 6 {\{13}\{10}\{13}$ }
+  IF FAIL STOP 1 INPUT timeout
+  PAUSE 1
+  OUTPUT logout\{13}
+  close
+  exit
+
+   The commands generated by Kermit during CONNECT (INPUT, IF FAIL,
+   PAUSE, and OUTPUT) have uppercase keywords; the commands typed by the
+   user are in whatever form the user typed them (in this case,
+   lowercase).
+
+   [ [460]Top ] [ [461]Contents ] [ [462]C-Kermit Home ] [ [463]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.12. Pattern Matching
+
+   A pattern is a character string that is used to match other strings.
+   Patterns can contain metacharacters that represent special actions
+   like "match any single character", "match zero or more characters",
+   "match any single character from a list", and so on. The best known
+   application of patterns is in file specifications that contain
+   wildcards, as in "send *.txt", meaning "send all files whose names end
+   with .txt".
+
+   Patterns are also used in increasingly many other ways, to the extent
+   it is useful to point out certain important distinctions in the ways
+   in which they are used:
+
+   Anchored Patterns
+          If an anchored pattern does not begin with "*", it must match
+          the beginning of the string, and if it does not end with "*",
+          it must match the end of the string. For example, the anchored
+          pattern "abc" matches only the string "abc", not "abcde" or
+          "xyzabc" or "abcabc". The anchored pattern "abc*" matches any
+          string that starts with "abc"; the anchored pattern "*abc"
+          matches any string that ends with "abc"; the anchored pattern
+          "*abc*" matches any string that contains "abc" (including any
+          that start and/or end with it).
+
+   Floating Patterns
+          A floating pattern matches any string that contains a substring
+          that matches the pattern. In other words, a floating pattern
+          has an implied "*" at the beginning and end. You can anchor a
+          floating pattern to the beginning by starting it with "^", and
+          you can anchor it to the end by ending it with "$" (see
+          examples below).
+
+   Wildcards
+          A wildcard is an anchored pattern that has the additional
+          property that "*" does not match directory separators.
+
+   This terminology lets us describe Kermit's commands with a bit more
+   precision. When a pattern is used for matching filenames, it is a
+   wildcard, except in the TEXT-PATTERNS and BINARY-PATTERNS lists and
+   /EXCEPT: clauses, in which case directory separators are not
+   significant (for example, a BINARY-PATTERN of "*.exe" matches any file
+   whose name ends in .exe, no matter how deeply it might be buried in
+   subdirectories). When Kermit parses a file specification directly,
+   however, it uses the strict wildcard definition. For example, "send
+   a*b" sends all files whose names start with "a" and end with "b" in
+   the current directory, and not any files whose names end with "b" that
+   happen to be in subdirectories whose names start with "a". And as
+   noted, wildcards are anchored, so "delete foo" deletes the file named
+   "foo", and not all files whose names happen to contain "foo".
+
+   Most other patterns are anchored. For example:
+
+  if match abc bc ...
+
+   does not succeed (and you would be surprised if it did!). In fact, the
+   only floating patterns are the ones used by commands or functions that
+   search for patterns in files, arrays, or strings. These include:
+
+     * The GREP and TYPE /MATCH commands.
+     * The \fsearch(), \frsearch(), and \farraylook() functions.
+
+   Thus these are the only contexts in which explicit anchors ("^" and
+   "$") may be used:
+
+   grep abc *.txt
+          Prints all lines containing "abc" in all files whose names end
+          with ".txt".
+
+   grep ^abc *.txt
+          Prints all lines that start with "abc" in all ".txt" files.
+
+   grep abc$ *.txt
+          Prints all lines that end with "abc" in all ".txt" files.
+
+   grep ^a*z$ *.txt
+          Prints all lines that start with "a" and end with "z" in all
+          ".txt" files.
+
+   Similarly for TYPE /PAGE, /fsearch(), /frsearch(), and \farraylook().
+
+   Here is a brief summary of anchored and floating pattern equivalences:
+
+  Anchored   Floating
+    abc       ^abc$
+    *abc      abc$
+    abc*      ^abc
+    *abc*     abc
+
+   [ [464]Top ] [ [465]Contents ] [ [466]C-Kermit Home ] [ [467]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.13. Dates and Times
+
+   C-Kermit's comprehension of date-time formats is considerably expanded
+   in version 8.0. Any command that reads dates, including the DATE
+   command itself, or any switch, such as the /BEFORE: and /AFTER:
+   switches, or any function such as \fcvtdate(), now can understand
+   dates and times expressed in any ISO 8601 format, in Unix "asctime"
+   format, in FTP MDTM format, and in practically any format used in RFC
+   822 or RFC 2822 electronic mail, with or without timezones, and in a
+   great many other formats as well. HELP DATE briefly summarizes the
+   acceptable date-time formats.
+
+   Furthermore, C-Kermit 8.0 includes a new and easy-to-use form of
+   date-time arithmetic, in which any date or time can be combined with a
+   "delta time", to add or subtract the desired time interval (years,
+   months, weeks, days, hours, minutes, seconds) to/from the given date.
+   And new functions are available to compare dates and to compute their
+   differences.
+
+   As you can imagine, all this requires quite a bit of "syntax". The
+   basic format is:
+
+  [ date ] [ time ] [ delta ]
+
+   Each field is optional, but in most cases (depending on the context)
+   there must be at least one field. If a date is given, it must come
+   first. If no date is given, the current date is assumed. If no time is
+   given, an appropriate time is supplied depending on whether a date was
+   supplied. If no delta is given, no arithmetic is done. If a delta is
+   given without a date or time, the current date and time are used as
+   the base.
+
+   Date-time-delta fields are likely to contain spaces (although they
+   need not; space-free forms are always available). Therefore, in most
+   contexts -- and notably as switch arguments -- date-time information
+   must be enclosed in braces or doublequotes, for example:
+
+  send /after:"8-Aug-2001 12:00 UTC" *.txt
+
+   Kermit's standard internal format for dates and times is:
+
+  yyyymmdd hh:mm:ss
+
+   for example:
+
+  20010208 10:28:01
+
+   Date-times can always be given in this format. yyyy is the 4-digit
+   year, mm is the two-digit month (1-12; supply leading zero for
+   Jan-Sep), dd is the 2-digit day (leading zero for 1-9), hh is the hour
+   (0-23), mm the minute (0-59), ss the second (0-59), each with leading
+   zero if less than the field width. The date and time can be separated
+   by a space, an underscore, a colon, or the letter T. The time is in
+   24-hour format. Thus the various quantites are at the following fixed
+   positions:
+
+Position  Contents                    
+   1-4    Year   (4 digits, 0000-9999)
+   5-6    Month  (2 digits, 1-12)
+   7-8    Day    (2 digits, 1-31)
+   9      Date-Time Separator (space, :, _, or the letter T)
+  10-11   Hour   (2 digits, 0-23)
+  12      Hour-Minute Separator (colon)
+  13-14   Minute (2 digits, 0-59)
+  15      Minute-Second Separator (colon)
+  16-17   Second (2 digits, 0-59)
+
+   Example:
+
+  19800526 13:07:12  26 May 1980, 13:07:12 (1:07:12PM)
+
+   This is the format produced by the DATE command and by any function
+   that returns a date-time. It is suitable for lexical comparison and
+   sorting, and for use as a date-time in any Kermit command. When this
+   format is given as input to a command or function, various date-time
+   separators (as noted) are accepted:
+
+  19800526 13:07:12  26 May 1980, 13:07:12 (1:07:12PM)
+  20010208_10:28:35  2 February 2001, 10:28:35 AM
+  18580101:12:00:00  1 January 1858, noon
+  20110208T00:00:00  2 February 2011, midnight
+
+   Certain other special date-time formats that are encountered on
+   computer networks are recognized:
+
+   Asctime Format
+          This is a fixed format used by Unix, named after Unix's
+          asctime() ("ASCII time") function. It is always exactly 24
+          characters long. Example: Fri Aug 10 16:38:01 2001
+
+   Asctime with Timezone
+          This is like Asctime format, but includes a 3-character
+          timezone between the time and year. It is exactly 28 characters
+          long. Example: Fri Aug 10 16:38:01 GMT 2001
+
+   E-Mail Format
+          E-mail date-time formats are defined in [468]RFC 2822 with a
+          fair amount of flexibility and options. The following examples
+          are typical of e-mails and HTTP (web-page) headers:
+
+  Sat, 14 Jul 2001 11:49:29                (No timezone)
+  Fri, 24 Mar 2000 14:19:59 EST            (Symbolic timezone)
+  Tue, 26 Jun 2001 10:19:45 -0400 (EDT)    (GMT Offset + comment)
+
+   FTP MDTM Format
+          This is the date-time format supplied by FTP servers that
+          support the (not yet standard but widely used nevertheless)
+          MDTM command, by which the FTP client asks for a file's
+          modification time:
+
+  yyyymmddhhmmss[.ffff]
+
+          where yyyy is the 4-digit year, mm is the 2-digit month, and so
+          on, exactly 14 digits long. An optional fractional part
+          (fraction of second) may also be included, separated by a
+          decimal point (period). Kermit rounds to the nearest second.
+          Example:
+
+  20020208102835.515                       (8 February 2002 10:28:36 AM)
+
+    8.13.1. The Date
+
+   The date, if given, must precede the time and/or delta, and can be in
+   many, many formats. For starters, you can use several symbolic date
+   names in place of actual dates:
+
+   NOW
+          This is replaced by the current date and time. The time can not
+          be overriden (if you want to supply a specific time, use TODAY
+          rather than NOW).
+
+   TODAY
+          This is replaced by the current date and a default time of
+          00:00:00 is supplied, but can be overridden by a specific time;
+          for example, if today is 8 February 2002, then "TODAY" is
+          "20020802 00:00:00" but "TODAY 10:28" is "20020802 10:28:00".
+
+   TOMORROW
+          Like TODAY, but one day later (if today is 8 February 2002,
+          then "TOMORROW" is "20020803 00:00:00" but "TOMORROW 16:30" is
+          "20020803 16:30:00").
+
+   YESTERDAY
+          Like TODAY, but one day earlier.
+
+   MONDAY, TUESDAY, WEDNESDAY, ..., SUNDAY
+          The date on the given day of the week, today or later. A
+          default time of 00:00:00 is supplied but can be overridden.
+          Example: "SATURDAY 12:00" means next Saturday (or today, if
+          today is Saturday) at noon.
+
+   You can give an explicit date in almost any conceivable format, but
+   there are some rules:
+
+     * If a date is given, it must have three fields: day, month, and
+       year; the order can vary (except that the month can not be last).
+     * If names are used for days, months, etc, they must be English.
+     * The year must lie between 0000 and 9999, inclusive.
+     * All calendar calculations use Gregorian dating, so calculated
+       dates for years prior to 1582 (or later, depending on the country)
+       will not agree with historical dates. Other forms of dating (e.g.
+       Hebrew, Chinese) are not supported.
+
+   Various date-field separators are accepted: hyphen, slash, space,
+   underscore, period. The same field separator (if any) must be used in
+   both places; for example 18-Sep-2001 but not 18-Sep/2001. Months can
+   be numeric (1-12) or English names or abbreviations. Month name
+   abbreviations are normally three letters, e.g. Apr, May, Jun, Jul.
+   Capitalization doesn't matter.
+
+   Here are a few examples:
+
+  18 Sep 2001                              (English month, abbreviated)
+  18 September 2001                        (English month, spelled out)
+  2001 Sept 18                             (Year, month, day)
+  18-Sep-2001                              (With hyphens)
+  18/09/2001                               (All numeric with slashes)
+  18.09.2001                               (Ditto, with periods)
+  18_09_2001                               (Ditto, with underscores)
+  09/18/2001                               (See below)
+  2001/09/18                               (See below)
+  September 18, 2001                       (Correspondence style)
+  Sep-18-2001                              (Month-day-year)
+  20010918                                 (Numeric, no separators)
+
+   You can also include the day of the week with a specific date, in
+   which case it is accepted (if it is a valid day name), but not
+   verified to agree with the given date:
+
+  Tue, 18 Sep 2001                         (Abbreviated, with comma)
+  Tue,18 Sep 2001                          (Comma but no space)
+  Tue 18 Sep 2001                          (Abbreviated, no comma)
+  Tuesday 18 Sep 2001                      (Spelled out)
+  Tuesday, 18 Sep 2001                     (etc)
+  Friday, 18 Sep 2001                      (Accepted even if not Friday)
+
+   In all-numeric dates with the year last, such as 18/09/2001, Kermit
+   identifies the year because it's 4 digits, then decides which of the
+   other two numbers is the month or day based on its value. If both are
+   12 or less and are unequal, the date is ambiguous and is rejected. In
+   all-numeric dates with the year first, the second field is always the
+   month and the third is the day. The month never comes last. A date
+   with no separators is accepted only if it is all numeric and has
+   exactly eight digits, and is assumed to be in yyyymmdd format.
+
+  20010918                                 (18-Sep-2001 00:00:00)
+
+   or 14 digits (as in FTP MDTM format):
+
+  20010918123456                           (18-Sep-2001 12:34:56)
+
+   You can always avoid ambiguity by putting the year first, or by using
+   an English, rather than numeric, month. A date such as 09/08/2001
+   would be ambiguous but 2001/09/08 is not, nor is 09-Aug-2001.
+
+   Until the late 1990s, it was common to encounter 2-digit years, and
+   these are found to this day in old e-mails and other documents. Kermit
+   accepts these dates if they have English months, and interprets them
+   according to the windowing rules of [469]RFC 2822: "If a two digit
+   year is encountered whose value is between 00 and 49, the year is
+   interpreted by adding 2000, ending up with a value between 2000 and
+   2049. If a two digit year is encountered with a value between 50 and
+   99, or any three digit year is encountered, the year is interpreted by
+   adding 1900."
+
+   If you need to specify a year prior to 1000, use leading zeros to
+   ensure it is not misinterpreted as a "non-Y2K-compliant" modern year:
+
+  7-Oct-77                                 (19771007 00:00:00)
+  7-Oct-0077                               (00771007 00:00:00)
+
+    8.13.2. The Time
+
+   The basic time format is hh:mm:dd; that is hours, minutes, seconds,
+   separated by colons, perhaps with an optional fractional second
+   separated by a decimal point (period). The hours are in 24-hour
+   format; 12 is noon, 13 is 1pm, and so on. Fields omitted from the
+   right default to zero. Fields can be omitted from the left or middle
+   by including the field's terminating colon. Examples:
+
+  11:59:59                                 (11:59:59 AM)
+  11:59                                    (11:59:00 AM)
+  11                                       (11:00:00 AM)
+  11:59:59.33                              (11:59:59 AM)
+  11:59:59.66                              (Noon)
+  03:21:00                                 (3:21:00 AM)
+  3:21:00                                  (3:21:00 AM)
+  15:21:00                                 (3:21:00 PM)
+  :21:00                                   (00:21:00 AM)
+  ::01                                     (00:00:01 AM)
+  11::59                                   (11:00:59 AM)
+
+   Leading zeros can be omitted, but it is customary and more readable to
+   keep them in the minute and second fields:
+
+  03:02:01                                 (03:02:01 AM)
+  3:02:01                                  (03:02:01 AM)
+  3:2:1                                    (03:02:01 AM)
+
+   AM/PM notation is accepted if you wish to use it:
+
+  11:59:59                                 (11:59:59 AM)
+  11:59:59AM                               (11:59:59 AM)
+  11:59:59A.M.                             (11:59:59 AM)
+  11:59:59am                               (11:59:59 AM)
+  11:59:59a.m.                             (11:59:59 AM)
+  11:59:59PM                               (11:59:59 PM = 23:59:59)
+  11:59:59P.M.                             (11:59:59 PM = 23:59:59)
+  11:59:59pm                               (11:59:59 PM = 23:59:59)
+  11:59:59p.m.                             (11:59:59 PM = 23:59:59)
+
+   You can omit the colons if you wish, in which case Kermit uses the
+   following rules to interpret the time:
+
+    1. 6 digits is hh:mm:ss, e.g. 123456 is 12:34:56.
+    2. 5 digits is h:mm:ss, e.g. 12345 is 1:23:45.
+    3. 4 digits is hh:mm, e.g. 1234 is 12:34.
+    4. 3 digits is h:mm, e.g. 123 is 1:23.
+    5. 2 digits is hh, e.g. 12 is 12:00.
+    6. 1 digit is h (the hour), e.g. 1 is 1:00.
+
+   Examples:
+
+  1                                        (01:00:00 AM)
+  10                                       (10:00:00 AM)
+  230                                      (02:30:00 AM)
+  230pm                                    (02:30:00 PM = 14:30:00)
+  1115                                     (11:15:00 AM)
+  2315                                     (11:15:00 PM = 23:15:00 PM)
+  23150                                    (02:31:50 AM)
+  231500                                   (23:15:00 PM)
+
+    8.13.3. Time Zones
+
+   If a time is given, it can (but need not) be followed by a time zone
+   designator. If no time zone is included, the time is treated as local
+   time and no timezone conversions are performed.
+
+   The preferred time zone designator is the UTC Offset, as specified in
+   [470]RFC 2822: a plus sign or minus sign immediately followed by
+   exactly four decimal digits, signifying the difference in hh (hours)
+   and mm (minutes) from Universal Coordinated Time (UTC, also known as
+   Greenwich Mean Time, or GMT), with negative numbers to the West and
+   positive numbers to the East. For example:
+
+  Fri, 13 Jul 2001 12:54:29 -0700
+
+   indicates a local time of 12:54:29 that is 07 hours and 00 minutes
+   behind (less than, East of) Universal Time. The space is optional, so
+   the example could also be written as:
+
+  Fri, 13 Jul 2001 12:54:29-0700
+
+   The following symbolic time zones are also accepted, as specified by
+   [471]RFC 2822 and/or in ISO 8601:
+
+  GMT  =  +0000       Greenwich Mean Time
+  Z    =  +0000       Zulu (Zero Meridian) Time
+  UTC  =  +0000       Universal Coordinated Time
+  UT   =  +0000       Universal Time
+  EDT  =  -0400       Eastern (USA) Daylight Time
+  EST  =  -0500       Eastern (USA) Standard Time
+  CDT  =  -0500       Central (USA) Daylight Time
+  CST  =  -0600       Central (USA) Standard Time
+  MDT  =  -0600       Mountain (USA) Daylight Time
+  MST  =  -0700       Mountain (USA) Standard Time
+  PDT  =  -0700       Pacific (USA) Daylight Time
+  PST  =  -0800       Pacific (USA) Standard Time
+
+   Note that GMT, Z, UTC, and UT all express the same concept: standard
+   (not daylight) time at the Zero Meridian. UTC, by the way, is an
+   international standard symbol and does not correspond to the order of
+   the English words, Universal Coordinated Time, but it happens to have
+   the same initial letters as these words. Of course hundreds of other
+   symbolic timezones and variations exist, but they are not
+   standardized, and are therefore not supported by Kermit.
+
+   When a time zone is included with a time, the time is converted to
+   local time. In case the conversion crosses a midnight boundary, the
+   date is adjusted accordingly. Examples converting to EST (Eastern USA
+   Standard Time = -0500):
+
+ 11:30:00      =  11:30:00
+ 11:30:00 EST  =  11:30:00
+ 11:30:00 GMT  =  06:30:00
+ 11:30:00 PST  =  14:30:00
+ 11:30:00Z     =  06:30:00
+ 11:30PM GMT   =  18:30:00
+ 11:30 -0500   =  11:30:00
+ 11:30 -0800   =  08:30:00
+ 11:30 +0200   =  04:30:00
+
+   Unlike most of Kermit's other date-time conversions, timezone
+   knowledge (specifically, the offset of local time from UTC) is
+   embodied in the underlying operating system, not in Kermit itself, and
+   any conversion errors in this department are the fault of the OS. For
+   example, most UNIX platforms do not perform conversions for years
+   prior to 1970.
+
+    8.13.4. Delta Time
+
+   Date/time expressions can be composed of a date and/or time and a
+   delta time, or a delta time by itself. When a delta time is given by
+   itself, it is relative to the current local date and time. Delta times
+   have the following general format:
+
+  {+,-}[number units][hh[:mm[:ss]]]
+
+   In other words, a delta time always starts with a plus or minus sign,
+   which is followed by a "part1", a "part2", or both. The "part1", if
+   given, specifies a number of days, weeks, months, or years; "part2"
+   specifies a time in hh:mm:ss notation. In arithmetic terms, these
+   represents some number of days or other big time units, and then a
+   fraction of a day expressed as hours, minutes, and seconds; these are
+   to be added to or subtracted from the given (or implied) date and
+   time. The syntax is somewhat flexible, as shown by the following
+   examples:
+
+  +1 day                (Plus one day)
+  +1day                 (Ditto)
+  +1d                   (Ditto)
+  + 1 day               (Ditto)
+  + 1 day 3:00          (Plus one day and 3 hours)
+  +1d3:00               (Ditto)
+  +1d3                  (Ditto)
+  +3:00:00              (Plus 3 hours)
+  +3:00                 (Ditto)
+  +3                    (Ditto)
+  +2 days               (Plus 2 days)
+  -12 days 7:14:22      (Minus 12 days, 7 hours, 14 minutes, and 22 seconds)
+
+   The words "week", "month", and "year" can be used like "day" in the
+   examples above. A week is exactly equivalent to 7 days. When months
+   are specified, the numeric month number of the date is incremented or
+   decremented by the given number, and the year and day adjusted
+   accordingly if necessary (for example, 31-Jan-2001 +1month =
+   03-Mar-2001 because February does not have 31 days). When years are
+   specified, they are added or subtracted to the base year. Examples
+   (assuming the current date is 10-Aug-2001 and the current time is
+   19:21:11):
+
+  18-Sep-2001 +1day              (20010918 00:00:00)
+  today +1day                    (20010811 00:00:00)
+  now+1d                         (20010811 19:21:11)
+  + 1 day                        (20010811 19:21:11)
+  + 1 day 3:14:42                (20010811 22:35:54)
+  + 7 weeks                      (20010928 19:21:11)
+  +1d3:14:42                     (20010811 22:35:54)
+  +1w3:14:42                     (20010817 22:35:54)
+  +1m3:14:42                     (20010910 22:35:54)
+  +1y3:14:42                     (20020810 22:35:54)
+  2 feb 2001 + 10 years          (20110208 00:00:00)
+  2001-02-08 +10y12              (20110208 12:00:00)
+  31-dec-1999 23:59:59+00:00:01  (20000101 00:00:00)
+  28-feb-1996 +1day              (19960229 00:00:00) (leap year)
+  28-feb-1997 +1day              (19970301 00:00:00) (nonleap year)
+  28-feb-1997 +1month            (19970328 00:00:00)
+  28-feb-1997 +1month 11:59:59   (19970328 11:59:59)
+  28-feb-1997 +20years           (20170228 00:00:00)
+  28-feb-1997 +8000years         (99970228 00:00:00)
+
+   For compatibility with VMS, the following special delta-time format is
+   also accepted:
+
+  +number-hh:mm:ss
+  -number-hh:mm:ss
+
+   (no spaces). The hyphen after the number indicates days. It
+   corresponds exactly to the Kermit notation:
+
+  +numberdhh:mm:ss
+  -numberdhh:mm:ss
+
+   The following forms all indicate exactly the same date and time:
+
+  18-Sep-2001 12:34:56 +1-3:23:01
+  18-Sep-2001 12:34:56 +1d3:23:01
+  18-Sep-2001 12:34:56 +1 day 3:23:01
+
+   and mean "add a day plus 3 hours, 23 minutes, and 1 second" to the
+   given date.
+
+   Note that delta times are not at all the same as UTC offsets; the
+   former specifies an adjustment to the given date/time and the latter
+   specifies that the local time is a particular distance from Universal
+   Time, for example:
+
+  11-Aug-2001 12:34:56 -0800          (20010811 16:34:56 -- UTC Offset)
+  11-Aug-2001 12:34:56 -08:00         (20010811 04:34:56 -- Delta time)
+
+   If you give a time followed by a modifer that starts with a + or -
+   sign, how does Kermit know whether it's a UTC offset or a delta time?
+   It is treated as a UTC offset if the sign is followed by exactly four
+   decimal digits; otherwise it is a delta time. Examples (for USA
+   Eastern Daylight Time):
+
+  11-Aug-2001 12:34:56 -0800          (20010811 16:34:56 -- UTC Offset)
+  11-Aug-2001 12:34:56 -08:00         (20010811 04:34:56 -- Delta time)
+  11-Aug-2001 12:34:56 -800           (20010811 04:34:56 -- Delta time)
+  11-Aug-2001 12:34:56 -8             (20010811 04:34:56 -- Delta time)
+
+   The first example says that at some unknown place which is 8 hours
+   ahead of Universal Time, the time is 12:34:56, and this corresponds to
+   16:34:56 in Eastern Daylight time. The second example says to subtract
+   8 hours from the local time. The third and fourth are delta times
+   because, even though a colon is not included, the time does not
+   consist of exactly 4 digits.
+
+   When a delta time is written after a timezone, however, there is no
+   ambiguity and no syntax distinction is required:
+
+  11-Aug-2001 12:34:56 -0800 -0800    (20010811 08:34:56)
+  11-Aug-2001 12:34:56 -0800 -08:00   (Ditto)
+  11-Aug-2001 12:34:56 -08:00 -08:00  (Illegal)
+
+    8.13.5. The DATE Command
+
+   Obviously a great many combinations of date, time, time zone, and
+   delta time are possible, as well as many formatting options. The
+   purpose of all this flexibility is to comply with as many standards as
+   possible -- Internet RFCs, ISO standards, and proven corporate
+   standards -- as well as with notations commonly used by real people,
+   in order that dates and times from the widest variety of sources can
+   be assigned to a variable and used in any date-time field in any
+   Kermit command.
+
+   You can test any date-and/or-time format with the DATE command, which
+   converts it to standard yyyymmdd hh:mm:ss format if it is understood,
+   or else gives an explicit error message (rather than just "BAD DATE"
+   as in previous C-Kermit releases) to indicate what is wrong with it.
+   Examples (on Tuesday, 31 July 2001 in New York City, Eastern Daylight
+   Time, UTC -0400):
+
+  DATE command argument                   Result           
+  12:30                                   20010731 12:30:00
+  12:30:01                                20010731 12:30:01
+  12:30:01.5                              20010731 12:30:02
+  1230                                    20010731 12:30:00
+  230                                     20010731 02:30:00
+  230+1d                                  20010801 02:30:00
+  230+1d3:00                              20010801 05:30:00
+  20010718 19:21:15                       20010718 19:21:15
+  20010718_192115                         20010718 19:21:15
+  20010718T192115                         20010718 19:21:15
+  18 Jul 2001 +0400                       20010717 23:59:59
+  18 Jul 2001 192115                      20010718 19:21:15
+  18 Jul 2001 192115.8                    20010718 19:21:16
+  18-Jul-2001T1921                        20010718 19:21:00
+  18-Jul-2001 1921Z                       20010718 15:21:00
+  18-Jul-2001 1921 GMT                    20010718 15:21:00
+  18-Jul-2001 1921 UTC                    20010718 15:21:00
+  18-Jul-2001 1921 Z                      20010718 15:21:00
+  18-Jul-2001 1921Z                       20010718 15:21:00
+  18-Jul-2001 1921 -04:00:00              20010718 19:21:00
+  21-Jul-2001_08:20:00am                  20010721 08:20:00
+  21-Jul-2001_8:20:00P.M.                 20010721 20:20:00
+  Fri Jul 20 11:26:25 2001                20010720 11:26:25
+  Fri Jul 20 11:26:25 GMT 2001            20010720 07:26:25
+  Sun, 9 Apr 2000 06:46:46 +0100          20000409 01:46:46
+  Sunday, 9 Apr 2000 06:46:46 +0100       20000409 01:46:46
+  now                                     20010731 19:41:12
+  today                                   20010731 00:00:00
+  today 09:00                             20010731 09:00:00
+  tomorrow                                20010801 00:00:00
+  tomorrow 09:00                          20010801 09:00:00
+  tomorrow 09:00 GMT                      20010801 05:00:00
+  yesterday                               20010730 00:00:00
+  yesterday 09:00                         20010730 09:00:00
+  + 3 days                                20010803 00:00:00
+  +3 days                                 20010803 00:00:00
+  +3days                                  20010803 00:00:00
+  + 3days                                 20010803 00:00:00
+  + 3 days 09:00                          20010803 09:00:00
+  + 2 weeks                               20010814 00:00:00
+  + 1 month                               20010831 00:00:00
+  - 7 months                              20001231 00:00:00
+  + 10 years                              20110731 00:00:00
+  friday                                  20010803 00:00:00
+  saturday                                20010804 00:00:00
+  sunday                                  20010805 00:00:00
+  monday                                  20010806 00:00:00
+  tuesday                                 20010731 00:00:00
+  wednesday                               20010801 00:00:00
+  thursday                                20010802 00:00:00
+  friday 07:00                            20010803 07:00:00
+  thursday 1:00pm                         20010802 13:00:00
+  thursday 1:00pm GMT                     20010802 09:00:00
+  Thu, 10 Nov 94 10:50:47 EST             19941110 10:50:47
+  Fri, 20 Oct 1995 18:35:15 -0400 (EDT)   19951020 18:35:15
+  31/12/2001                              20011231 00:00:00
+  12/31/2001                              20011231 00:00:00
+  2001-July-20                            20010720 00:00:00
+  2001-September-30                       20010930 00:00:00
+  30-September-2001                       20010930 00:00:00
+  Sep 30, 2001 12:34:56                   20010930 12:34:56
+  September 30, 2001                      20010930 00:00:00
+  September 30, 2001 630                  20010930 06:30:00
+  September 30 2001 630                   20010930 06:30:00
+  Sep-30-2001 12:34:59                    20010930 12:34:59
+  20010807113542.014                      20010807 11:35.42
+  20010807113542.014Z                     20010807 07:35:42
+
+    8.13.6. New Date-Time Functions
+
+   In the following descriptions, date-time function arguments are the
+   same free-format date-time strings discussed above, with the same
+   defaults for missing fields. They are automatically converted to
+   standard format internally prior to processing.
+
+   \fcvtdate(d1)
+          Converts the date-time d1 to standard format and local time.
+          This function is not new, but now it accepts a wider range of
+          argument formats that can include timezones and/or delta times.
+          If the first argument is omitted, the current date and time are
+          assumed. The optional second argument is a format code for the
+          result:
+
+     n1 = 1: yyyy-mmm-dd hh:mm:ss (mmm = English 3-letter month
+     abbreviation)
+     n1 = 2: dd-mmm-yyyy hh:mm:ss (ditto)
+     n1 = 3: yyyymmddhhmmss (all numeric)
+
+   \futcdate(d1)
+          Converts the date-time d1 to Universal Coordinated Time (UTC),
+          also known as GMT or Zulu or Zero-Meridian time. The default d1
+          is NOW. If d1 is a valid date-time, the UTC result is returned
+          in standard format, yyyymmdd hh:ss:mm.
+
+   \fcmpdates(d1,d2)
+          Compares two free-format date-times, d1 and d2, and, if both
+          arguments are valid, returns a number: -1 if d1 is earlier than
+          (before) d2; 0 if d1 is the same as d2; 1 if d1 is later than
+          (after) d2.
+
+   \fdiffdates(d1,d2)
+          Computes the difference between two free-format date-times, d1
+          and d2. If both arguments are valid, returns a delta time which
+          is negative if d1 is earlier than (before) d2 and positive
+          otherwise. If d1 and d2 are equal, the result is "+0:00".
+          Otherwise, the result consists of the number of days, hours,
+          minutes, and seconds that separate the two date-times. If the
+          number of days is zero, it is omitted. If the number of days is
+          nonzero but the hours, minutes, and seconds are all zero, the
+          time is omitted. if the seconds are zero, they are omitted.
+
+   \fdelta2secs(dt)
+          Converts a delta time to seconds. For example, "+1d00:00:01" to
+          86401. Valid delta times must start with a + or - sign. Days
+          are accepted as time units, but not years, months, or weeks. If
+          the result would overflow a computer long word (as would happen
+          with 32-bit long words when the number of days is greater than
+          24854), the function fails.
+
+   HINT: Although Kermit has a number of built-in date and time
+   variables, it doesn't have a single one suitable for writing a
+   timestamp. For this you would normally use something like "\v(ndate)
+   \v(time)". But \fcvtdate() (with no arguments) is equivalent: it
+   returns the current date and time in yyyymmdd hh:mm:ss format,
+   suitable for time stamping.
+
+    8.13.7. Date-Time Programming Examples
+
+   Here's a macro that converts any date-time to UTC, which you might use
+   if C-Kermit didn't already have a \futcdate() function:
+
+  define utcdate {
+      .local := \fcvtdate(\%*)                 ; 1.
+      .tmp := \fcvtdate(\m(local)UTC)          ; 2.
+      .offset := \fdiffdate(\m(local),\m(tmp)) ; 3.
+      .utc := \fcvtdate(\m(local)\m(offset))   ; 4.
+      sho mac utc                              ; 5.
+  }
+
+   Brief explanation: Line 1 converts the macro argument, a free-format
+   date-time, to standard-format local time. Line 2 appends the "UTC"
+   timezone to the local time and converts the result to local time. In
+   other words, we take the same time as the local time, but pretend it's
+   UTC time, and convert it to local time. For example, if New York time
+   is 4 hours ahead of UTC, then 6:00pm New York time is 2:00pm UTC. Line
+   3 gets the difference of the two results (e.g. "+04:00"). Line 4
+   appends the difference (delta time) to the local time, and converts it
+   again, which adds (or subtracts) the UTC offset to the given time.
+   Line 5 displays the result.
+
+   Here's a script that opens a web page, gets its headers into an array,
+   scans the array for the "Last-Modified:" header, and inteprets it:
+  http open www.columbia.edu
+  if fail stop 1 HTTP OPEN failed
+  http /array:a head index.html /dev/null
+  if fail stop 1 HTTP GET failed
+  show array a
+  for \%i 1 \fdim(&a) 1 {
+      .\%x := \findex(:,\&a[\%i])
+      if not \%x continue
+      .tag := \fleft(\&a[\%i],\%x-1)
+      .val := \fltrim(\fsubstr(\&a[\%i],\%x+1))
+      if ( eq "\m(tag)" "Last-Modified" ) {
+          echo HTTP Date: \m(val)
+          .rdate := \fcvtdate(\m(val))
+          echo {Standard Date (local): \m(rdate)}
+          echo {Standard Date (UTC):   \futcdate(\m(rdate))}
+          break
+      }
+  }
+  http close
+
+   The result:
+
+  HTTP Date: Mon, 13 Aug 2001 20:05:42 GMT
+  Standard Date (local): 20010813 16:05:42
+  Standard Date (UTC):   20010813 20:05:42
+
+   As you can see, Kermit had no trouble decoding the date-time-string
+   from the website, converting to local time, and converting back to UTC
+   with no conflicts or loss of information. If it had been in any other
+   known format, the result would have been the same.
+
+   Now suppose we want to download the web page only if it is newer than
+   our local copy. The \fdate(filename) function (which returns the
+   modification date-time of the given file) and the new \fcmpdates()
+   function make it easy. Insert the following just before the BREAK
+   statement:
+
+  if ( < 0 \fcmpdates(\m(rdate),\fdate(index.html)) ) {
+     echo GETTING index.html...
+     http get index.html index.html
+     if success echo HTTP GET OK
+  } else {
+     echo index.html: no update needed
+  }
+  http close
+  exit
+
+   This says, "if 0 is less than the comparison of the remote file date
+   and the local file date, get the remote file, otherwise skip it." And
+   it automatically reconciles the time-zone difference (if any).
+
+   It would be nice to be able to extend this script into a
+   general-purpose website updater, but unfortunately HTTP protocol
+   doesn't provide any mechanism for the client to ask the server for a
+   list of files, recursive or otherwise.
+
+   [ [472]Top ] [ [473]Contents ] [ [474]C-Kermit Home ] [ [475]Kermit
+   Home ]
+     _________________________________________________________________
+
+  8.14. Trapping Keyboard Interruption
+
+   Normally when you type Ctrl-C and Kermit is in command mode (as
+   opposed to CONNECT mode) with COMMAND INTERRUPTION ON (as it is unless
+   you have set it OFF), Kermit interrupts any command that is currently
+   in progress, and if a command file or macro is executing, rolls the
+   command stack back to top level, closing all open command files,
+   deactivating all macros, deallocating all local variables and arrays,
+   and leaving you at the command prompt.
+
+   Suppose, however, you want certain actions to occur when a script is
+   interrupted; for example, closing open files, writing log entries, or
+   displaying summary results. You can do this by defining a macro named
+   ON_CTRLC. When Ctrl-C is detected, and a macro with this name is
+   defined, Kermit executes it from the current command level, thus
+   giving it full access to the environment in which the interruption
+   occurred, including local variables and open files. Only when the
+   ON_CTRLC macro completes execution is the command stack rolled back to
+   top level.
+
+   Once the ON_CTRLC macro is defined, it can be executed only once. This
+   is to prevent recursion if the user types Ctrl-C while the ON_CTRLC
+   macro is executing. If you type Ctrl-C while the Ctrl-C macro is
+   active, this does not start a new copy of ON_CTRLC; rather, it returns
+   to the top-level command prompt. After the ON_CTRLC macro returns, it
+   has been removed from the macro table so if you want to use it again
+   or install a different Ctrl-C trap, you must execute a new DEFINE
+   ON_CTRLC command. In any case, as always when you interrupt a script
+   with Ctrl-C, its completion status is FAILURE.
+
+   Normally the ON_CTRLC macro would be defined in the command file or
+   macro to which it applies, and should be declared LOCAL. This way, if
+   the command file or macro completes successfully without being
+   interrupted, the ON_CTRLC definition disappears automatically.
+   Otherwise the definition would still be valid and the macro would be
+   executed, probably out of context, the next time you typed Ctrl-C.
+
+   Here's a simple example of a command file that sets a Ctrl-C trap for
+   itself:
+
+  local on_ctrlc              ; Make Ctrl-C trap local to this command file.
+  define on_ctrlc {           ; Define the ON_CTRLC macro.
+      echo Interrupted at \v(time).
+      echo Iterations: \%n
+  }
+  xecho Type Ctrl-C to quit
+  for \%n 1 999 1 {           ; Prints a dot every second until interrupted.
+      sleep 1
+      xecho .
+  }
+  echo Finished normally at \v(time) ; Get here only if not interrupted.
+  decrement \%n
+  echo Iterations: \%n
+
+   This prints a summary no matter whether it completes normally or is
+   interrupted from the keyboard. In both cases the trap is automatically
+   removed afterwards.
+
+   For an example of how to use ON_CTRLC to debug scripts, see
+   [476]Section 8.1.
+
+   [ [477]Top ] [ [478]Contents ] [ [479]C-Kermit Home ] [ [480]Kermit
+   Home ]
+  __________________________________________________________________________
+
+9. S-EXPRESSIONS
+
+   This section is primarily for those who want to write
+   calculation-intensive scripts, especially if they require
+   floating-point arithmetic, and/or for those who are familiar with the
+   LISP programming language.
+
+   Ever since C-Kermit version 5 was released in 1988, scripting has been
+   one of its major attractions, and arithmetic is a key part of it.
+   Versions 5 and 6 included integer arithmetic only, using traditional
+   algebraic notation, e.g.:
+
+  echo \fevaluate(3*(2+7)/2)
+  13
+
+   C-Kermit 7.0 added support for floating-point arithmetic, but only
+   through function calls:
+
+  echo \ffpdivide(\ffpmultiply(3.0,\ffpadd(2.0,7.0)),2.0)
+  13.5
+
+   C-Kermit 8.0 introduces a third form of arithmetic that treats
+   integers and floating-point numbers uniformly, is easier to read and
+   write, and executes very quickly:
+
+  (/ (* 3 (+ 2 7)) 2)
+  13.5
+
+   But first some background.
+
+   The Kermit command and scripting language differs from true
+   programming languages (such as C or Fortran) in many ways; one of the
+   most prominent differences is the way in which variables are
+   distinguished from constants. In a command language, words are taken
+   literally; for example, the Unix shell:
+
+  cat foo.bar
+
+   displays the file named foo.bar. Whereas in a programming language
+   like C, words are assumed to be variables:
+
+  s = foo.bar;    /* Assigns the value of foo.bar to the variable s */
+
+   To make a programming language take words literally, you have to quote
+   or "escape" them:
+
+  s = "foo.bar";  /* Assigns a pointer to the string "foo.bar" to the variable
+s */
+
+   The opposite holds for command languages: to get them to treat a word
+   as a variable rather than a constant, you have to escape them. For
+   example, in the Unix shell:
+
+  foo=123         ; Assign value 123 to variable foo.
+  echo foo        ; Prints "foo"
+  echo $foo       ; Prints "123"
+
+   And in Kermit:
+
+  define foo 123  ; Assign value 123 to variable foo.
+  echo 123        ; This prints "123".
+  echo foo        ; This prints "foo".
+  echo \m(foo)    ; This prints "123".
+
+   In other words, character strings (such as "foo" above) are
+   interpreted as literal strings, rather than variable names, except in
+   special commands like DEFINE that deal specifically with variable
+   names (or in numeric contexts as explained in [481]Section 8.2). The
+   special "escape" character (dollar sign ($) for the shell, backslash
+   (\) for Kermit) indicates that a variable is to be replaced by its
+   value.
+
+   The requirement to escape variable names in command languages normally
+   does not impose any special hardship, but can add a considerable
+   notational burden to arithmetic expressions, which are typically full
+   of variables. Especially in Kermit when floating point numbers are
+   involved, where you must use special \ffpxxx() functions, e.g.
+   "\ffpadd(\m(a),\m(b))" rather than the simple "+" operator to add two
+   floating-point numbers together, because the original arithmetic
+   handler doesn't support floating point (this might change in the
+   future). To illustrate, the general formula for the area of a triangle
+   is:
+
+  sqrt(s * (s - a) * (s - b) * (s - c))
+
+   where a, b, and c are the lengths of the triangle's three sides and:
+
+  s = (a + b + c) / 2
+
+   Except in special cases (e.g. a = 3, b = 4, c = 5), the result has a
+   fractional part so the computation must be done using floating-point
+   arithmetic. We can create a Kermit 7.0 function for this as follows:
+
+  def area {
+      local s t1 t2 t3
+      assign s \ffpdiv(\ffpadd(\ffpadd(\%1,\%2),\%3),2.0)
+      assign t1 \ffpsub(\m(s),\%1)
+      assign t2 \ffpsub(\m(s),\%2)
+      assign t3 \ffpsub(\m(s),\%3)
+      return \ffpsqrt(\ffpmul(\m(s),\ffpmul(\m(t1),\ffpmul(\m(t2),\m(t3)))))
+  }
+
+   But as you can see, this is rather cumbersome. Note, in particular,
+   that arithmetic functions like \ffpadd(), \ffpmul(), etc, take exactly
+   two operands (like their symbolic counterparts + and *), so obtaining
+   the product of three or more numbers (as we do in this case) is
+   awkward.
+
+   Using the alternative S-Expression notation, we can reduce this to a
+   form that is both easier to read and executes faster (the details are
+   explained later):
+
+  def newarea {
+      (let s (/ (+ \%1 \%2 \%3) 2.0))
+      (sqrt (* s (- s \%1) (- s \%2) (- s \%3)))
+  }
+
+   In both examples, the \%1..3 variables are the normal Kermit macro
+   arguments, referenced by the normal escaping mechanism. For increased
+   readability, we can also assign the macro arguments \%1, \%2, and \%3
+   to the letters a, b, and c corresponding to our formula:
+
+def newarea {
+    (let a \%1 b \%2 c \%3)
+    (let s (/ (+ a b c) 2.0))
+    (sqrt (* s (- s a) (- s b) (- s c)))
+}
+
+   And now the Kermit function reads almost like the original formula.
+   Here Kermit behaves more like a regular programming language. In an
+   S-Expression, macro names need not be escaped when they are used as
+   the names of numeric variables.
+
+   [ [482]Top ] [ [483]Contents ] [ [484]C-Kermit Home ] [ [485]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.1. What is an S-Expression?
+
+   The S-Expression concept is borrowed from the Lisp programming
+   language. "S-Expression" is short for Symbolic Expression (itself
+   sometimes shortened to SEXP). S-Expressions provide a kind of
+   Alternative Mini-Universe within the Kermit command language when the
+   regular rules don't apply, a universe enclosed in parentheses.
+
+   C-Kermit does not pretend to be a full Lisp interpreter; only the
+   arithmetic parts of Lisp have been incorporated: S-Expressions that
+   operate on numbers and return numeric values (plus extensibility
+   features described in [486]Section 9.8, which allow some degree of
+   string processing).
+
+   An S-Expression is a list of zero or more items, separated by spaces,
+   within parentheses. Examples:
+
+  ()
+  (1)
+  (a)
+  (+ a 1)
+  (* 2 a b)
+
+   If the S-Expression is empty, it has the NIL (empty) value. If it is
+   not empty and the first item is an operator (such as + or *), there
+   can be zero or more subsequent items, called the operands:
+
+  (+ 1 2)
+
+   Here the operator is "+" and the operands are "1" and "2", and the
+   value of the S-Expression is the value of the operation (in this case
+   3). The operator always comes first, which is different from the
+   familiar algebraic notation; this because S-Expression operators can
+   have different numbers of operands:
+
+  (+ 1)
+  (+ 1 2)
+  (+ 1 2 3 4 5 6 7 8 9)
+
+   If the first item in the S-Expression is not an operator, then it must
+   be a variable or a number (or a macro; see [487]Section 9.8), and the
+   S-Expression can only contain one item; in this case, the
+   S-Expression's value is the value of the variable or number:
+
+  (a)
+  (3)
+
+   Operands can be numbers, variables that have numeric values, functions
+   that return numbers, or other S-Expressions. To illustrate an
+   S-Expression within an S-Expression, observe that:
+
+  (+ 1 2)
+
+   is equivalent to any of the following (plus an infinite number of
+   others):
+
+  (+ 1 (+ 1 1))
+  (+ (- 3 2) (/ 14 (+ 3 4)))
+
+   S-Expressions can be nested to any reasonable level; for example, the
+   value of the following S-Expression is 64:
+
+  (- (* (+ 2 (* 3 4)) (- 9 (* 2 2))) 6)
+
+   Operators have no precedence, implied or otherwise, since they can't
+   be mixed. The only exceptions are unary + and -, which simply indicate
+   the sign of a number:
+
+  (* 3 -1)
+
+   Order of evaluation is specified entirely by parentheses, which are
+   required around each operator and its operands: (+ a (* b c)) instead
+   of (a + b * c).
+
+   S-Expressions provide a simple and isolated environment in which
+   Kermit's macro names can be used without the \m(...) escaping that is
+   normally required. Given:
+
+  define a 1
+  define b 2
+  define c 3
+
+   Then:
+
+  (+ \m(a) \m(b) \m(c))
+
+   is equivalent to:
+
+  (+ a b c)
+
+   Within an S-Expression, as in other strictly numeric contexts
+   ([488]Section 8.2), any operand that starts with a letter is treated
+   as a Kermit macro name. In this context, abbreviations are not
+   accepted; variable names must be spelled out in full. Alphabetic case
+   is not significant; "a" and "A" are the same variable, but both are
+   different from "area".
+
+   Of course, regular Kermit variables and functions can be used in
+   S-Expressions in the normal ways:
+
+  (* \v(math_pi) (^ \%r 2))             ; Area of a circle with radius \%r
+  (+ \fjoin(&a))                        ; Sum of all elements of array \&a[]
+
+   [ [489]Top ] [ [490]Contents ] [ [491]C-Kermit Home ] [ [492]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.2. Integer and Floating-Point-Arithmetic
+
+   Normally, if all numbers in an S-Expression are integers, the result
+   is an integer:
+
+  (+ 1 1)                               ; Result is 2
+  (/ 9 3)                               ; Result is 3
+
+   If any of the operands is floating point, however, the result is also
+   floating point:
+
+  (+ 1 1.0)                             ; Result is 2.0
+  (/ 9.0 3)                             ; Result is 3.0
+
+   If all the operands are integers but the result has a fractional part,
+   the result is floating point:
+
+  (/ 10 3)                              ; Result is 3.333333333333333
+
+   To force an integer result in such cases, use the TRUNCATE operator:
+
+  (truncate (/ 10 3))                   ; Result is 3
+
+   Similarly, to force a computation to occur in floating point, you can
+   coerce one of its operands to FLOAT:
+
+  (+ 1 (float 1))                       ; Result is 2.0
+
+   The result is also floating point if the magnitude of any integer
+   operand, intermediate result, or the result itself, is larger than the
+   maximum for the underlying machine architecture:
+
+  (^ 100 100)
+
+   If the result is too large even for floating-point representation,
+   "Infinity" is printed; if it is too small to be distinguished from 0,
+   0.0 is returned.
+
+   Large numbers can be used and large results generated, but they are
+   accurate only to the precision of the underlying machine. For example,
+   the result of:
+
+ (+ 111111111111111111111 222222222222222222222)
+
+   should be 333333333333333333333, but 333333333333333300000.0 is
+   produced instead if the machine is accurate to only about 16 decimal
+   digits, even with coercion to floating-point. The order of magnitude
+   is correct but the least significant digits are wrong. The imprecise
+   nature of the result is indicated by the ".0" at the end. Contrast
+   with:
+
+ (+ 111111111 222222222)
+
+   which produces an exact integer result.
+
+   [ [493]Top ] [ [494]Contents ] [ [495]C-Kermit Home ] [ [496]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.3. How to Use S-Expressions
+
+   S-Expressions may be given as commands to C-Kermit. Any command whose
+   first character is "(" (left parenthesis) is interpreted as an
+   S-Expression.
+
+   If you enter an S-Expression at the C-Kermit> prompt, its result is
+   printed:
+
+  C-Kermit>(/ 10.0 3)
+   3.333333333333333
+  C-Kermit>
+
+   If an S-Expression is executed within a macro or command file, its
+   value is not printed. However, you can control the printing action
+   with:
+
+   SET SEXPRESSION ECHO { AUTO, ON, OFF }
+          AUTO is the default, meaning print the value at top level only;
+          ON means always print the value; OFF means never print it.
+
+   In any case, the value of the most recent S-Expression (and the
+   S-Expression itself) may be accessed programmatically through the
+   following variables:
+
+   \v(sexpression)
+          The S-Expression most recently executed.
+
+   \v(svalue)
+          The value of the S-Expression most recently executed.
+
+   Besides issuing S-Expressions as commands in themselves, you can also
+   execute them anywhere within a Kermit command, but in this case they
+   must be enclosed in a function call (otherwise they are taken
+   literally):
+
+   \fsexpression(s)
+          The argument "s" is an S-Expression; the outer parentheses may
+          be omitted. The value of the S-Expression is returned. Note
+          that since S-Expressions usually contain spaces, some form of
+          grouping or quoting might be needed in some contexts:
+
+  echo \fsexpression((+ 1 1))            ; Outer parentheses may be included
+  echo \fsexpr(+ 1 1)                    ; Outer parentheses may be omitted
+  echo Value = "\fsexp(+ 1 a)"           ; Can be embedded in strings
+  echo Value = \&a[\fsexp(/ b 2)]        ; Can be used in array subscripts
+  if = {\fsexp(+ 1 1)} 2 {               ; Braces needed here for grouping
+      echo One plus one still equals two
+  }
+
+   The IF statement illustrates how to use S-Expressions as (or in) IF or
+   WHILE conditions:
+
+     * Although S-Expressions and IF conditions are similar in
+       appearance, they are not interchangeable. Therefore you must use
+       \fsexpr() to let Kermit know it's an S-Expression rather than a
+       regular IF condition, or a boolean or algebraic expression within
+       an IF condition.
+     * In contexts where a single "word" is expected, you must enclose
+       the \fsexp() invocation in braces if the S-Expression contains
+       spaces (and most of them do).
+
+   If an S-Expression is the last command executed in a macro, its value
+   becomes the return value of the macro; no RETURN command is needed.
+   Example:
+
+  def newarea {
+      (let s (/ (+ \%1 \%2 \%3) 2.0))
+      (sqrt (* s (- s \%1) (- s \%2) (- s \%3)))
+  }
+
+   This is equivalent to (but more efficient than):
+
+  def newarea {
+      (let s (/ (+ \%1 \%2 \%3) 2.0))
+      return \fsexp(sqrt (* s (- s \%1) (- s \%2) (- s \%3)))
+  }
+
+   When an S-Expression is entered as a command -- that is, the first
+   nonblank character of the command is a left parenthesis -- then it is
+   allowed to span multiple lines, as many as you like, until the first
+   left parenthesis is matched:
+
+  (let s (/
+          (+
+           \%1
+           \%2
+           \%3
+           )
+          2.0
+          )
+       )
+  (sqrt (*
+         s
+         (- s \%1)
+         (- s \%2)
+         (- s \%3)
+         )
+        )
+
+   The S-Expression concept lends itself easily to embedding and
+   recursion, but the depth to which recursion can occur is limited by
+   the resources of the computer (memory size, address space, swap space
+   on disk) and other factors. There is no way that C-Kermit can know
+   what this limit is, since it varies not only from computer to
+   computer, but also from moment to moment. If resources are exhausted
+   by recursion, C-Kermit simply crashes; there's no way to trap this
+   error. However, you can set a depth limit on S-Expressions:
+
+   SET SEXPRESSION DEPTH-LIMIT number
+          Limits the number of times the S-Expression reader can invoke
+          itself without returning to the given number. The default limit
+          is 1000. This limit applies to S-Expressions embedded within
+          other S-Expressions as well as to S-Expressions that invoke
+          recursive macros. If the limit is exceeded, Kermit prints
+          "?S-Expression depth limit exceeded" and returns to its prompt.
+          More about recursion in [497]Section 9.8.
+
+   You can also test the depth programmatically:
+
+   \v(sdepth)
+          The current S-Expression invocation depth. The depth includes
+          both nesting level and recursion. For example, in:
+          (foo (foo (foo (foo (foo))))), the innermost (foo) is at depth
+          5.
+
+   Help, completion, and syntax checking are not available within an
+   S-Expression. If you type ? within an S-Expression, it says:
+
+  C-Kermit>(? S-Expression ("help sexp" for details)
+
+   As it says, typing "help sexp" will display a brief help text.
+
+   The SHOW SEXPRESSION command displays current SET SEXPRESSION settings
+   and related information.
+
+   [ [498]Top ] [ [499]Contents ] [ [500]C-Kermit Home ] [ [501]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.4. Summary of Built-in Constants and Operators
+
+   Three constants are built in:
+
+     * PI, whose value is the value of pi (the quotient of circumference
+       of any circle and its diameter, 3.141592653...) to the underlying
+       machine's precision;
+     * T, which always has the value 1, which signifies truth in Kermit
+       logical expressions or S-Expressions;
+     * NIL, which always has the empty value, and can serve as a False
+       truth value.
+
+   These constants are specific to S-Expressions and are not visible
+   outside them. They may not be used as the target of an assignment. So,
+   for example:
+
+  (setq t 0)   Fails
+  assign t 0   Succeeds but this is not the same T!
+
+   E (the base of natural logarithms, 2.7182818184...) is not built in
+   since it is not intrinsic in most Lisp dialects. If you want E to be
+   the base of natural logarithms you can:
+
+  (setq e (exp 1))
+
+   Operators are either symbols (such as "+") or words. Words must be
+   spelled out in full, not abbreviated. Differences of alphabetic case
+   are ignored.
+
+   The most basic operation in S-Expressions is evaluation:
+
+   EVAL [ s-expression or variable or number [ another [ another ... ] ]
+          ]
+          Evaluates its operands and returns the value of the last one
+          evaluated. Examples:
+
+  (eval)                                0
+  (eval 1)                              1
+  (eval a)                              value of a
+  (eval (+ 1 a))                        value of a+1
+  (eval (setq a 1) (setq b (+ a 0.5)))  value of b (= a+0.5)
+
+          You can use "." as a shorthand for EVAL:
+
+  (.)
+  (. 1)
+  (. a)
+  (. (+ 1 a))
+  (. (setq a 1) (setq b (+ a 0.5)))
+
+   Opposite of EVAL is the operator that suppresses evaluation of its
+   operand:
+
+   QUOTE item
+          The value (quote item) is "item". If the item is itself an
+          S-Expression, the result is the S-Expression with the outer
+          parentheses stripped. Examples:
+
+  (quote)                               (illegal)
+  (quote a)                             a
+  (quote hello)                         hello
+  (quote (this is a string))            this is a string
+  (quote this is a string)              (illegal)
+
+          A shorthand notation is also accepted for quoting:
+          'a is equivalent to (quote a). And therefore:
+          '(a b c) is equivalent to (quote (a b c)).
+          More about quoting in [502]Section 9.8.
+
+   STRING item
+          Is a combination of EVAL and QUOTE. It evaluates the item as an
+          S-Expression, and then puts quotes around the result (more
+          about this in [503]Section 9.8).
+
+   The following operators assign values to variables:
+
+   SETQ [ variable [ value [ variable [ value [ ... ] ] ] ] ]
+          Applies to global variables. For each variable given: if a
+          value is not given, the variable is undefined. If a value is
+          given, assigns the value to the variable. The value may be a
+          number, a variable, or anything that resolves to a number
+          including an S-Expression. Returns the value of the last
+          assignment. Examples:
+
+  (setq)             Does nothing, returns NIL.
+  (setq a)           Undefines a, returns NIL.
+  (setq a 1)         Assigns 1 to a, returns 1.
+  (setq a 1 b 2)     Assigns 1 to a, 2 to b, returns 2.
+  (setq a 1 b 2 c)   Assigns 1 to a, 2 to b, undefines c, returns NIL.
+
+   To undefine a variable that is not the final one in the list, give it
+   a value of "()" or NIL:
+
+  (setq a () b 2)    Undefines a, assigns 2 to b, returns 2.
+  (setq a nil b 2)   Ditto.
+
+   Note that a variable can be used right away once it has a value:
+
+  (setq a 1 b a)     Assigns 1 to a, the value of a (1) to b, returns 1.
+
+   The results of SETQ (when used with macro names) can be checked
+   conveniently with SHOW MACRO, e.g:
+
+  show mac a b c
+
+   LET [ variable [ value [ variable [ value [ ... ] ] ] ] ]
+          Like SETQ, but applies to local variables. Note that "local" is
+          used in the Kermit sense, not the Lisp sense; it applies to the
+          current Kermit command level, not to the current S-Expression.
+
+   If you want to use SETQ or LET to assign a value to a backslash
+   variable such as \%a or \&a[2], you must double the backslash:
+
+  (setq \\%a 3)
+  (setq \\%b (+ \%a 1))
+  (setq \\&a[2] (setq (\\%c (+ \%a \%b))))
+
+   In other words:
+
+     * Double the backslash when you want to indicate the variable's
+       NAME;
+     * Don't double the backslash when you want its VALUE.
+
+   See [504]Section 9.6 for a fuller explanation of variable syntax and
+   scope.
+
+   Here's a summary table of arithmetic operators; in the examples, a is
+   2 and b is -1.3:
+
+  Operator  Description                            Example           Result
+  +         Adds all operands (0 or more)          (+ a b)           0.7
+  -         Subtracts all operands (0 or more)     (- 9 5 2 1)       1
+  *         Multiplies all operands (0 or more)    (* a (+ b 1) 3)  -1.80
+  /         Divides all operands (2 or more)       (/ b a 2)        -0.325
+  ^         Raise given number to given power      (^ 3 2)           9
+  ++        Increments variables                   (++ a 1.2)        3.2
+  --        Decrements variables                   (-- 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
+  FLOAT     Convert an integer to floating-point   (float 1)         1.0
+  TRUNCATE  Integer part of floating-point operand (truncate 3.333)  3
+  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
+  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-in-radians               (sin (/ pi 2))    1.0
+  COS       Cosine of angle-in-radians             (cos pi)         -1.0
+  TAN       Tangent of angle-in-radians            (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
+
+   The ++ and -- operators are also assignment operators and work just
+   like SETQ and LET in their interpretations of operators and operands,
+   but:
+
+     * Each target variable must already be defined and have a numeric
+       value;
+     * The assignment value is the amount by which to increment or
+       decrement the variable.
+     * If an assignment value is not given, 1 is used.
+
+   If you include more than one variable-value pair in a ++ or --
+   expression, every variable (except, optionally, the last) must be
+   followed by a value. Examples:
+
+  (++ a)                Equivalent to (setq a (+ a 1)) and to (++ a 1)
+  (++ a 2)              Equivalent to (setq a (+ a 2))
+  (-- a (* 2 pi))       Equivalent to (setq a (- a (* 2 pi)))
+  (++ a 1 b 1 c 1 d)    Equivalent to four SETQs incrementing a,b,c,d by 1.
+
+   Another group of operators forms the predicates. These return a "truth
+   value", in which 0 (or NIL) is false, and 1 or any other nonzero
+   number is true.
+
+  Operator  Description                            Example           Result
+  = (or ==) Operands are equal                     (= 1 1.0)         1
+  !=        Operands are not equal                 (!= 1 1.0)        0
+  <         Operands in strictly ascending order   (< 1 2 3)         1
+  <=        Operands in ascending order            (<= 1 1 2 3)      1
+  >         Operands in strictly descending order  (> 3 2 1)         1
+  >=        Operands in descending order           (<= 3 3 2 1)      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
+
+   The Exclusive OR of two values is true if one value is true and the
+   other value is false.
+
+   And another group operates on bits within an integer word:
+
+  Operator  Description                            Example           Result
+  &         Bitwise AND                            (& 7 2)           2
+  |         Bitwise OR                             (| 1 2 3 4)       7
+  #         Bitwise Exclusive OR                   (# 3 1)           2
+  ~         Reverses all bits                      (~ 3)            -4
+
+   These operators coerce their operands to integer by truncation if
+   necessary. The result of bit reversal is hardware dependent.
+
+   The final category of operator works on truth values:
+
+  Operator  Description                            Example           Result
+  IF        Conditional evaluation                 (if (1) 2 3)      2
+
+   IF (predicate) (s1) [ (s2) ]
+          The IF operator is similar to Kermit's IF command. If the
+          predicate is true (i.e. evaluates to a nonzero number), the
+          first S-Expression (s1) is evaluated and its value is returned.
+          Otherwise, if (s2) is given, it is evaluated and its value
+          returned; if (s2) is not given, nothing happens and the NIL
+          (empty) value is returned.
+
+   You can group multiple expressions in the s1 and s2 expressions using
+   EVAL (or "."):
+
+  (if (< a 0) (eval (setq x 0) (setq y 0)) (eval (setq x a) (setq y b)))
+
+   or equivalently:
+
+  (if (< a 0) (. (setq x 0) (setq y 0)) (. (setq x a) (setq y b)))
+
+   Each operator has its own requirement as to number and type of
+   operands. In the following table, "number" means any kind of number --
+   integer or floating-point -- or a variable, function, macro, or
+   S-Expression that returns a number; "vname" means variable name,
+   "fpnumber" means a floating-point number (or anything that resolves to
+   one), and "integer" means integer (or anything that resolves to one).
+   "truthvalue" means anything that resolves to a value of zero or an
+   empty value (which indicates false) or a nonzero value (which
+   indicates true). "any" means any kind of value, including none at all.
+
+  Operator  Number of operands   Type of operands    Returns
+  EVAL  (.) 0 or more            S-Expression        Last value (default NIL)
+  STRING    1                    S-Expression        string
+  QUOTE (') 1                    word                string
+  SETQ      0 or more            vname value pairs   Last value (default NIL)
+  LET       0 or more            vname value pairs   Last value (default NIL)
+  +         0 or more            number              number     (default 0)
+  -         0 or more            number              number     (default 0)
+  *         0 or more            number              number     (see note (1))
+  /         2 or more            number              number
+  ^         2 or more            number              number
+  ++        1 or more            vname value pairs   Result of last increment
+  --        1 or more            vname value pairs   Result of last decrement
+  ABS       1                    number              number
+  MAX       1 or more            number              number
+  MIN       1 or more            number              number
+  MOD (%)   2                    number              number
+  FLOAT     1                    number              fpnumber
+  TRUNCATE  1                    number              integer
+  CEILING   1                    number              integer
+  FLOOR     1                    number              integer
+  ROUND     1                    number              integer
+  SQRT      1                    number              fpnumber
+  EXP       1                    number              fpnumber
+  SIN       1                    number              fpnumber
+  COS       1                    number              fpnumber
+  TAN       1                    number              fpnumber
+  LOG       1                    number              fpnumber
+  LOG10     1                    number              fpnumber
+  = (==)    1 or more            number              truthvalue
+  !=        1 or more            number              truthvalue
+  <         1 or more            number              truthvalue
+  <=        1 or more            number              truthvalue
+  >         1 or more            number              truthvalue
+  >=        1 or more            number              truthvalue
+  AND (&&)  1 or more            truthvalue          truthvalue
+  OR  (||)  1 or more            truthvalue          truthvalue
+  XOR       2                    truthvalue          truthvalue
+  NOT (!)   1                    truthvalue          truthvalue
+  &         1 or more            number (see note 2) integer
+  |         1 or more            number (see note 2) integer
+  #         2                    number (see note 2) integer
+  ~         1                    number (see note 2) integer
+  IF        2 or 3               truthvalue,any,any  any
+
+   Operators that don't require any arguments return the default values
+   shown.
+
+    1. The value of "*", when used as an operator, is initially "1" and
+       the value of the most recent S-Expression thereafter, as in Franz
+       Lisp. This is handy when doing a series of calculations by hand:
+  C-Kermit>(* 13272.42 0.40)
+   5308.968
+  C-Kermit>(/ * 2)
+   2654.4840
+  C-Kermit>
+    2. The bitwise operators coerce their operands to integer by
+       truncation.
+
+   [ [505]Top ] [ [506]Contents ] [ [507]C-Kermit Home ] [ [508]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.5. Variables
+
+   As noted elsewhere in this discussion, all backslash items (variables
+   such as \%a, macro parameters such as \%1, array elements such as
+   \&a[\%i], built-in variables such as \v(ndate), built-in functions
+   such as \fjoin(), macro names enclosed in \m(), \s(), or \:(), etc)
+   are evaluated at "top level" before the S-Expression is sent to the
+   S-Expression reader. To use a backslash variable as the target of an
+   assignment (e.g. by SETQ, LET, ++, or --), you must double the
+   backslash, e.g. (setq \\%r 1234). This is discussed at greater length
+   in the next section.
+
+   Thus S-Expression reader generally deals only with macro names (not
+   backslash items) as variables. It is important to understand how the
+   reader handles macro names. There are fundamentally two kinds of
+   S-Expressions: those that contain a single element, such as:
+
+  (foo)
+
+   and those that contain more than one element:
+
+  (foo a b c)
+
+   If an S-Expression contains only one element, and it is the name of a
+   macro, the macro's definition is examined. If the definition is a
+   number (integer or floating-point, positive or negative), then this
+   becomes the value of the expression. If the definition starts with '
+   (apostrophe), then the quoted word or string is the value of the
+   expression (explained in [509]Section 9.8). Otherwise, the macro is
+   assumed to be composed of Kermit commands (possibly including
+   S-Expressions), which are executed. If the macro has a RETURN value,
+   or it executes an S-Expression as its last command, the result becomes
+   the value of the S-Expression; otherwise the result is empty.
+
+   For S-Expressions that contain more than one element, and the first
+   element is the name of a macro, then this macro is executed with the
+   arguments that are given, after the arguments are evaluated by the
+   S-Expression reader. Likewise, If the first element is a built-in
+   operator, then it is applied to the operands after they are evaluated.
+   In both cases, each operand is fed to the S-Expression reader
+   recursively for evaluation. If an operand is a number or a quoted
+   string, it is used as-is. But if it's a macro name, this degenerates
+   into the first case, and the previous paragraph applies.
+
+   Examples:
+
+  define foo 123
+  (foo)                                Result: 123
+  define foo 'abc
+  (foo)                                Result: abc
+  define foo '(one two three)
+  (foo)                                Result: one two three
+  define foo return \frandom(1000)
+  (foo)                                Result: 713 (or other number)
+  define foo (+ a b)
+  (foo)                                Result: The sum of a and b
+
+   A more difficult example:
+
+  define foo abc
+  (foo)                                Result: ???
+
+   The result in the last example depends on the definition of abc:
+
+     * If it has no definition, an error occurs; otherwise:
+     * If the definition is an S-Expression, the result is the
+       S-Expression's value; otherwise:
+     * If the definition consists of Kermit commands, they are executed.
+       But in this case "(foo)" produces the empty result, because it
+       doesn't RETURN anything.
+
+   The use of macros as S-Expression operators is described in
+   [510]Section 9.8.
+
+   [ [511]Top ] [ [512]Contents ] [ [513]C-Kermit Home ] [ [514]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.6. Assignments and Scope
+
+   The assignment operators SETQ and LET apply to global and local
+   variables, respectively. SETQ and LET are standard Lisp operators
+   adapted to Kermit scoping rules. When the operands are numeric or
+   arithmetic, SETQ is equivalent to Kermit's EVALUATE command:
+
+  (setq a (+ 1 2))
+  evaluate a 1 + 2
+
+   When the operand is a string, SETQ is equivalent to DEFINE:
+
+  (setq a '(this is a string))
+  define a this is a string
+
+   In the first case, both statements create a macro named "a" with a
+   value of 3. But in neither case is the macro "a" necessarily global.
+   If either of these commands executes in an environment (i.e. macro
+   invocation level) where a "local a" command has been given, the "a"
+   macro is global to that environment, but is not visible outside it.
+
+   LET is equivalent to the Kermit LOCAL command, followed by the
+   corresponding EVALUATE:
+
+  (let a (+ 1 2))
+
+   is equivalent to:
+
+  local a
+  evaluate a 1 + 2
+
+   Again, "local" in this context applies to the Kermit macro invocation
+   stack, not to the S-Expression nesting level. To illustrate, recall
+   our "newarea" macro:
+
+def newarea {
+    (let a \%1 b \%2 c \%3)
+    (let s (/ (+ a b c) 2.0))
+    (sqrt (* s (- s a) (- s b) (- s c)))
+}
+
+   Because SETQ and LET expressions return a value, they can be placed
+   within a larger S-Expression. In this case we can replace the first
+   reference to the "s" variable by its defining expression:
+
+def newarea {
+    (let a \%1 b \%2 c \%3)
+    (sqrt (* (let s (/ (+ a b c) 2.0)) (- s a) (- s b) (- s c)))
+}
+
+   This would not work if LET were local to the S-Expression, but it
+   works nicely in the context of Kermit macros. The previous definition
+   is equivalent to:
+
+def newarea {
+    local a b c s
+    (setq a \%1 b \%2 c \%3)
+    (sqrt (* (setq s (/ (+ a b c) 2.0)) (- s a) (- s b) (- s c)))
+}
+
+   In both cases, the variables a, b, c, and s are local to the "newarea"
+   macro, and global within it.
+
+   Multiple assignments can be handled in several ways. Here is the
+   obvious way to initialize a series of variables to the same value:
+
+  (setq a 0)
+  (setq b 0)
+  (setq c 0)
+  (setq s 0)
+
+   Here is a more compact and efficient way of doing the same thing:
+
+  (setq a 0 b 0 c 0 s 0)
+
+   However, in case the value was more complex, it's better to put only
+   one copy of it in the S-Expression; in this case we rely on the fact
+   that SETQ returns the value of its last assignment:
+
+  (setq a (setq b (setq c (setq s (* x (^ y 2))))))
+
+   Similarly, to set a series of variables to x, x+1, x+2, ...
+
+  (setq c (+ (setq b (+ (setq a (+ (setq s x) 1)) 1)) 1))
+
+   In the last example, you can see why "last" does not always correspond
+   to "rightmost" (the leftmost variable "c" is assigned last).
+
+   If you are working with backslash variables like \%a or array elements
+   like \&a[1], remember two rules:
+    1. Don't put spaces inside array brackets.
+    2. You must double the backslash when using SETQ, LET, ++, or -- to
+       assign a value to a backslash variable.
+
+   Examples of assigning to a backslash variable:
+
+  (setq x 1)
+  (setq \\%a 0)
+  (setq \\&a[x+1] 1)
+  (++ \\%x)
+  (-- \\&a[x+2])
+
+   Examples of referring to a backslash variable's value:
+
+  (setq a (+ \%a 1))
+  (setq b (+ \%a \&a[1]))
+  (++ a \%x)
+  (-- b \&a[1])
+
+   The special notation is required because all backslashed items (\%x
+   variables, array elements, built-in \v(xxx) variables, and \fxxx()
+   function invocations) are evaluated in a single pass BEFORE the
+   S-Expression is executed; any other approach would result in
+   unacceptable performance. So, for example, in:
+
+  declare \&a[] = 1 2 3
+  define \%x 4
+  define \%y 0
+  (setq \\%y (+ \%x \&a[1]))
+
+   the S-Expression becomes:
+
+  (setq \%y (+ 4 1))
+
+   before it is sent to the S-Expression evaluator. If the backslash had
+   not been doubled on the assignment target, the result would have been:
+
+  (setq 0 (+ 4 1))
+
+   which is illegal because you can't assign a value to a number.
+   Conversely, if backslashes were doubled on right-hand-side values:
+
+  (setq \\%y (+ \\%x \\&a[1])
+
+   this too, would give an error (not numeric - "\%x").
+
+   If you omit the double backslash in the assignment target, the result
+   depends on whether the variable already has a value:
+
+  (setq \%a (* 3 3))
+
+   If \%a has a non-numeric single-word value, then this becomes the name
+   of the variable that is assigned by SETQ. To illustrate:
+
+  define \%a foo
+  echo \%a
+  foo
+  (setq \%a (* 3 3))
+  echo \%a
+  foo
+  show macro foo
+  foo = 9
+
+   If \%a has no value, a numeric value, or a multiword value, an
+   "invalid assignment" error occurs.
+
+   [ [515]Top ] [ [516]Contents ] [ [517]C-Kermit Home ] [ [518]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.7. Conditional Expressions
+
+   The IF operator provides a compact form of decision-making within
+   S-Expressions. An IF expression can stand wherever a number might
+   stand, as long is it returns a number. Here's a quick way to obtain
+   the average value of all the elements in an array that contains only
+   numbers:
+
+  (/ (+ \fjoin(&a)) (float \fdim(&a)))
+
+   This results in a "Divide by zero" error if the array is empty. If you
+   want to define the average value of an empty array to be 0 instead of
+   getting an error, you can use IF to check the array size:
+
+  (if \fdim(&a) (/ (+ \fjoin(&a)) (float \fdim(&a))) 0)
+
+   or equivalently:
+
+  (if (not \fdim(&a)) 0 (/ (+ \fjoin(&a)) (float \fdim(&a))))
+
+   Of course, IF can fit anywhere else into an S-Expression:
+
+  (setq a (+ b (if (< c 0) 0 c)))
+
+   and the IF expression can be as complex as you like:
+
+  (setq a (+ b (if (and (or (> x 0) (> y 0)) (< c 0) (> d 1) (!= e 0)) 1 0)))
+
+   and the "then" and "else" parts can contain multiple S-Expressions
+   enclosed within (EVAL ...):
+
+  (if x (eval (...) (...) (...)) (eval (...) (...) (...)))
+
+   AND and OR operators are guaranteed to "short circuit". If any operand
+   of AND is false, none of the subsequent operands is evaluated;
+   likewise, if an OR operand is true, no further operands are evaluated.
+
+   Bear in mind that the S-Expression IF is not the same as Kermit IF;
+   the condition is only allowed to be an S-Expression or a variable or
+   number, not the whole list of possibilities you see when you type "if
+   ?" at the C-Kermit> prompt. But keep reading...
+
+   [ [519]Top ] [ [520]Contents ] [ [521]C-Kermit Home ] [ [522]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.8. Extensibility
+
+   To extend the capabilities of S-Expressions, you can use Kermit macro
+   names as operators, with the following limitations:
+
+     * The macro must not have the same name as a built-in operator.
+     * You must use the full macro name, not an abbreviation.
+
+   And with the following enhancement:
+
+     * If the last statement executed by the macro is an S-Expression,
+       its value is returned automatically. In other words:
+
+  define bump (++ \%1)
+
+   is equivalent to:
+
+  define bump return \fsexpression(++ \%1)
+
+   Here's an example in which we define a FIBONACCI operator that returns
+   the nth element, n >= 0, of the Fibonacci series, 0 1 1 2 3 5 8 13 21
+   34 55, . . ., in which the first element is 0, the second is 1, and
+   each subsequent element is the sum of the two before it. This series
+   was devised by Leonardo Pisano, Filius Bonacci (Fibonacci for short)
+   in 1202 to describe how fast rabbits can breed, and also forms the
+   basis for the Golden Mean, the branching behavior of plants, the
+   spiral of a nautilus shell, etc. (Thanks to [523]Dat Thuc Nguyen for
+   December 2003 corrections to this section!)
+
+   We can write a FIBONACCI function as a macro easily with
+   S-Expressions:
+
+  define FIBONACCI {
+    (if (== \%1 0) 0
+        (if (== \%1 1) 1 (+ (fibonacci (- \%1 2)) (fibonacci (- \%1 1)))))
+  }
+
+   You can read this as:
+
+     If the argument (\%1) is 0, return a result of 0; if it is 1,
+     return 1; otherwise:
+     return the sum of fibonacci(argument - 2) and fibonacci(argument -
+     1)
+
+   Note that a RETURN statement is not needed, since S-Expressions
+   automatically set the return value of their containing macros.
+
+   For comparison, here's how it would be coded without S-Expressions:
+
+  define FIBONACCI {
+      if == \%1 0 {
+          return 0
+      } else if == \%1 1 {
+          return 1
+      } else {
+          return \feval(\fexec(fibonacci \feval(\%1-2)) -
+               + \fexec(fibonacci \feval(\%1-1)))
+      }
+  }
+
+   Now we can use the FIBONACCI function (whichever way you write it)
+   just as if it were a built-in operator:
+
+  (fibonacci 6)
+
+   Or:
+
+  (setq a 10)
+  (fibonacci a)
+
+   Within S-Expressions only (not outside them), S-Expressions themselves
+   can be used as macro arguments:
+
+  (setq a 2 b 4)
+  (setq x (fibonacci (* a b )))
+
+   The value of the S-Expression (in this case "8"), and not the
+   S-Expression itself, is sent to the macro.
+
+   Your macro is responsible for argument validation and error handling.
+   A robust Fibonacci macro would be more like this:
+
+  define FIBONACCI {
+      if < \v(argc) 2 end 1 ?\%0: Missing argument
+      if > \v(argc) 2 end 1 ?\%0: Too many arguments
+      if not integer \%1 end 1 ?\%0: Integers only
+      if < \%1 1 end 1 ?\%0: Argument out of range
+      (if (== \%1 0) 0
+         (if (== \%1 1) 1 (+ (fibonacci (- \%1 2)) (fibonacci (- \%1 1)))))
+  }
+
+   Recall that "END nonzero-number [ message ]" causes a macro invocation
+   to fail. When the macro is the operator in an S-Expression, this makes
+   the S-Expression fail too. Also note that our Fibonacci macro is just
+   an illustration, not a practical example. Since it is recursive (calls
+   itself), it won't work for large arguments because the call stack can
+   exceed available memory. See [524]Section 9.9.2 for a practical
+   alternative.
+
+   Kermit macros, when used as S-Expression operators, can do anything at
+   all except initiate file transfers: they can print messages on the
+   screen, read and write files, interact with the user, and so on. For
+   example, here's a macro ASKME that asks you to enter a number, makes
+   sure that you did, and then returns its value for use in the
+   S-Expression:
+
+  define ASKME {
+      local \%n
+      while true {
+          ask \%n { Number: }
+          if not def \%n continue
+          if not numeric \%n {
+              echo Not numeric - "\%n"
+              continue
+          }
+          break
+      }
+      return \%n
+  }
+  (setq a (* 2 (askme))) ; Get number from user, double it, assign result to a.
+
+   Here's a macro you can use to validate that a number is in a given
+   range:
+
+  define inrange {
+      if != \v(argc) 4 end 1 ?\%0: Wrong number of arguments
+      if ( < \%1 \%2 || > \%1 \%3 ) return 0
+      return 1
+  }
+
+   The first argument is the number to be checked, the second is the
+   minimum acceptable value, the third is the maximum. You can use this
+   (for example) in IF conditions:
+
+  define yes echo \%1 IS OK
+  define no echo \%1 IS NOT OK
+
+  (setq a -1 b 999)
+  (if (inrange a 0 100) (yes a) (no a))
+  (if (inrange b -1000 +1000) (yes b) (no b))
+
+   This is just an illustration, of course; there's already a built-in
+   operator to let you do range checking without help from macros:
+
+  (if (<= 0 a 100) (yes a) (no a))
+  (if (<= -1000 b +1000) (yes b) (no b))
+
+   To send string parameters to a macro, some kind of quoting is required
+   to tell the S-Expression parser to take a given "word" literally
+   rather than replacing it by its value. For this we use the Lisp QUOTE
+   operator:
+
+  define length return \flength(\%1)
+  (length (quote abcdefghijklmnopqrstuvwxyz))
+  26
+
+   This causes the string "abcdefghijklmnopqrstuvwxyz" to be sent
+   literally to the LENGTH macro. Kermit, like Lisp, also offers a
+   shortcut for QUOTE, that lets us quote a word by prefixing it with a
+   single quote (') character, also called apostophe (ASCII 39):
+
+  (length 'abcdefghijklmnopqrstuvwxyz)
+  26
+
+   The two forms are equivalent.
+
+   How the macro treats its arguments is up to the macro. In the example
+   above, the argument is treated as a literal string. However, it can
+   also be treated as a variable name:
+
+  define string This is a string
+  define length return \flength(\m(\%1))
+  (length 'string)
+  16
+
+   Note the construct \m(\%1). This means "the value of the macro whose
+   name is the value of
+   \%1". The value of \%1 in this case is the word "string", and the
+   value of the macro whose name is "string" is "This is a string".
+
+   What if the macro takes multiple arguments, or a variable number of
+   them? Here's a simple macro that prints a phrase that includes its
+   arguments:
+
+  define complain echo It's too \%*!
+
+   (Recall that \%* means "all arguments".)
+
+   It can be called in the traditional way:
+
+  complain hot                       Result: "It's too hot!"
+  complain cold and wet              Result: "It's too cold and wet!"
+
+   Or from an S-Expression if you quote the arguments:
+
+  (complain 'hot)                    Result: "It's too hot!"
+  (complain 'cold 'and 'wet)         Result: "It's too cold and wet!"
+
+   To group multiple words into a single argument, use parentheses:
+
+  (complain (quote (cold and wet)))  Result: "It's too cold and wet!"
+  (complain '(cold and wet))         Result: "It's too cold and wet!"
+
+   Note the difference:
+
+  (complain 'cold 'and 'wet)         Three arguments
+  (complain '(cold and wet))         One argument
+
+   Since the COMPLAIN macro uses \%* to refer to all its arguments, no
+   matter how many, it doesn't care which form you use. But it makes a
+   difference in cases where the macro refers to its arguments
+   individually.
+
+   To illustrate, let's consider a macro that receives the name of a
+   macro and its argument list and executes it with its arguments,
+   without knowing how many arguments there are. The following LOOP macro
+   is used to execute the given macro with the given argument list the
+   requested number of times:
+
+  def loop { local i, for i 1 \%1 1 do \%2 \%3 }
+
+   Within the LOOP macro, the first argument (\%1) is the loop count, \%2
+   is the macro name, and \%3 is the argument list. When the LOOP macro
+   is invoked traditionally like this:
+
+  loop 3 complain hot
+
+   it prints "It's too hot!" three times. To invoke it from an
+   S-Expression, you must quote both the macro name as well as the
+   argument, since in this case the macro name itself is an argument:
+
+  (loop 3 'complain 'hot)
+
+   Now what if you need to send different or variable numbers of
+   arguments to the LOOP macro? The LOOP macro can handle it already,
+   provided you group the arguments into LOOP's third argument (\%3). In
+   Kermit syntax, without grouping:
+
+  loop 3 complain cold and wet
+
+   prints "It's too cold!" three times ("and wet" is lost); but with
+   grouping (either of the following two forms):
+
+  loop 3 complain {cold and wet}
+  loop 3 complain "cold and wet"
+
+   the LOOP macro prints "It's too cold and wet!" three times as desired.
+
+   To do the same thing in an S-Expression, just use the Lisp forms of
+   quoting instead of the Kermit forms; the following two are equivalent:
+
+  (loop 3 'complain (quote (cold and wet)))
+  (loop 3 'complain '(cold and wet))
+
+   Here's a similar example in which we write a macro that shows both the
+   name and the value of one or more other macros, whose names are given
+   as arguments (similar to "show macro"):
+
+  define display {
+      local \%i
+      for \%i 1 \v(argc)-1 1 {
+          echo \&_[\%i] = \m(\&_[\%i])
+      }
+  }
+
+   (Recall that \&_[] is the macro's argument vector array, equivalent to
+   \%1, \%2, ...) The DISPLAY macro can be used in S-Expressions like
+   this:
+
+  (setq a 1 b 2 c 3)
+  (display 'a 'b 'c 'd)
+
+   which prints:
+
+  a = 1
+  b = 2
+  c = 3
+  d =
+
+   The names must be quoted to prevent their evaluation before they are
+   sent to the macro. This ability to pass variables "by name" to macros,
+   rather than by value, lets you write macros that change the values of
+   argument variables. For example, here's a macro that doubles the value
+   of its argument variable:
+
+  define double (++ \%1 \%1)
+
+   which you can call like this:
+
+  (setq a 12)
+  (double 'a)
+
+   In the macro, \%1 is replace by the variable name "a"; "(++ a a)" adds
+   "a" to itself, and sets the value of "a" to the result.
+
+   There are no built-in operators other than QUOTE, ', and STRING for
+   handling strings in S-Expressions, but using just these, plus macros
+   that use Kermit's regular string-handling features, you can easily
+   extend S-Expressions to do string manipulation:
+
+  define len return \flen(\%1)               Returns length of argument string
+  define cap return \fupper(\%1)             Uppercase argument string
+  define rev return \freverse(\%1)           Reverses argument string
+  define sub return \fsubstr(\%1,\%2,\%3)    Returns substring of arg string
+
+  (len '(this is a string))                  Result: 16
+  (rev '(this is a string))                  Result: gnirts a si siht
+  (rev (cap '(this is a string)))            Result: GNIRTS A SI SIHT
+  (sub (rev (cap '(this is a string))) 5 9)  Result: TS A SI S
+
+   You can assign a string to a macro name as follows:
+
+  (setq foo '(this is a string))
+  (setq foo (quote (this is a string)))
+
+   The two are exactly equivalent. In both cases, the macro "foo" has the
+   value:
+
+  '(this is a string)
+
+   so when it is retrieved it can be identified as a string rather than a
+   number or commands to be executed. Thus:
+
+  (setq foo (quote (this is a string)))
+  show macro foo
+  foo = '(this is a string)
+  (foo)
+  this is a string
+
+   Note the different results for "show macro foo" and "(foo)". The
+   former shows the internal definition; the latter evaluates the
+   variable, which removes the quoting. And perhaps more important, note
+   that if the apostrophe and surrounding parentheses were not stored as
+   part of the definition, (foo) would try to execute "this is a string"
+   as a command.
+
+   Given the assignment above, the following work as expected:
+
+  (len foo)                                  Result: 16
+  (rev foo)                                  Result: gnirts a si siht
+  (rev (cap foo))                            Result: GNIRTS A SI SIHT
+  (sub (rev (cap foo)) 5 8)                  Result: TS A SI S
+
+   Note that, unlike built-in S-Expression operators that return numbers
+   or truth values, these operators return strings. If you want to assign
+   their return values to other variables, you can do so:
+
+  (setq bar (rev (cap foo)))                 Result: GNIRTS A SI SIHT
+
+   But now the S-Expression processor doesn't know the value of "bar" is
+   supposed to be a string, rather than a macro to execute. For this you
+   need one final special operator, STRING. The STRING operator takes an
+   S-Expression as an operand, evaluates it, and then returns its value
+   enclosed in '(), so you can use the value as a string is subsequent
+   S-Expressions. Use STRING for referencing macros that return strings:
+
+  (setq bar (string (rev (cap foo))))        Result: '(GNIRTS A SI SIHT)
+
+   STRING is like QUOTE, except that it evaluates its operand before
+   applying the quoting, rather than taking the operand literally.
+
+   To reference backslash variables or functions that return string
+   values, you must use the regular quoting mechanisms:
+
+  (setq time '(\v(time)))
+  (setq date '(\v(date)))
+  assign \%r this is a string
+  (setq s1 '(\%r))
+
+   That's because backslash items are evaluated BEFORE the S-Expression
+   parser ever sees them, and the values of \v(time) and so on are not
+   valid S-Expressions, so STRING won't like them.
+
+   Finally a brief word on the touchy topic of quoting. Suppose you want
+   to include (say) literal parentheses in a string that will later be
+   processed by the S-Expression reader (or \fsplit() or \fword()).
+   Normally, you can't do this because parentheses are meaningful in
+   these contexts. To defeat the normal parsing rules, you can quote the
+   parentheses with backslash. However, due to the many levels of string
+   processing involved, a surprisingly large amount of backslashes might
+   be required, for example:
+
+  (setq s '(a b (c d) \\\\\\\\\\\\\\\\(e f (g h) x\\\\\\\\\\\\\\\\) j k))
+
+   This is nearly impossible to explain(*). Instead, just remember two
+   points:
+
+     * In situations like this, it's better to use DEFINE to create the
+       string, rather than SETQ. The example above requires only double
+       backslashes when DEFINE is used:
+  define s '(a b (c d) \\(e f (g h) x\\) j k)
+     * The level of quoting depends on how many levels of evaluation the
+       string must pass through, which is not always obvious. However,
+       the number of backslashes required in any given situation is
+       always a power of 2. So if 1 doesn't work, try 2; if 2 doesn't
+       work, try 4; if 4 doesn't work, try 8, 16, 32, and so on.
+
+   Considerations like this apply in any scripting language (shell, Tcl,
+   Perl, Python, etc). The situation is known as "Quoting Hell".
+
+   (*) If you really want an explanation, here it is:
+
+     * Every SEXP has its backslash items evaluated in a single pass at
+       top level before being passed to the SEXP reader, so \%1,
+       \v(ftime), etc, can be evaluated up front, freeing the SEXP reader
+       of having to know about such things, which in turn makes it much
+       more efficient. Therefore one level of quoting is lost right away,
+       and therefore you must double each backslash that is to be used as
+       a quote.
+     * When the SEXP reader sees '\', it treats it as a quote; discards
+       it and keeps the next character. Thus '\\' becomes '\'. This would
+       be the end of it, except that:
+     * The SEXP reader must call itself recursively on its operands, so
+       we must double any quotes in the operands: 2^2 = 4.
+     * If the result is to be passed as an argument to a macro, the
+       backslashes must again be doubled, because the macro processor
+       evaluates the arguments before sending them to the macro: 2^3 = 8.
+     * If the macro itself is to see the quotes, rather than just the
+       result of the quoting, the quotes must be doubled again: 2^4 = 16.
+
+   Moral: To create string constants in which grouping characters must be
+   quoted, use DEFINE rather than SETQ.
+
+   [ [525]Top ] [ [526]Contents ] [ [527]C-Kermit Home ] [ [528]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.9. Examples
+
+    9.9.1. Statistics
+
+   The following program computes statistics -- means, maxima, mimima,
+   variance, standard deviation, and correlation -- from data stored in
+   parallel arrays, \&x[] and \&y[], which can contain any mixture of
+   integer and floating-point numbers: positive, negative, or zero. Array
+   setup and validation are not shown. Except for the traditional FOR
+   loop and printing the results at the end, the entire computation is
+   done with S-Expressions:
+
+; Initialize sums, maxima, minima, and number of elements
+
+  (setq xsum 0 ysum 0 xsum2 0 ysum2 0 xysum 0)
+  (setq xmin (setq xmax \&x[1]) ymin (setq ymax \&y[1]))
+  (setq n \fdim(&x))
+
+; Loop through elements and accumulate sums, maxima, and minima
+
+  for i 1 n 1 {
+      (setq x \&x[i] y \&y[i])                    ; Notational convenience
+      (setq xmax (max xmax x) ymax (max ymax y))  ; X and Y maxima
+      (setq xmin (min xmin x) ymin (min ymin y))  ; X and Y minima
+      (++ xsum x ysum y)                          ; X and Y sums
+      (++ xsum2 (^ x 2) ysum2 (^ y 2))            ; Sum of X and Y squares
+      (++ xysum (* x y))                          ; Sum of XY products
+  }
+
+; Calculate results
+
+  (setq xmean (/ xsum n) ymean (/ ysum n))        ; Mean X and Y
+  (setq xss (- xsum2 (/ (^ xsum 2) n)))           ; Intermediate values
+  (setq yss (- ysum2 (/ (^ ysum 2) n)))
+  (setq xyss (- xysum (/ (* xsum ysum) n)))
+  (setq xvar (/ xss n) yvar (/ yss n))            ; X and Y variance
+  (setq sdx (sqrt xvar) sdy (sqrt yvar))          ; Std deviation in X and Y
+  (setq tmp (* xss yss))
+  (setq cc (if tmp (/ xyss (sqrt tmp)) 1.0))      ; Correlation coefficient
+  show macro xmean ymean xvar yvar sdx sdy cc     ; Print the results
+
+   The final "if tmp" check accounts for the possibility that both arrays
+   contain all 0's. Results can also be printed with "echo CC = \m(cc)",
+   or any other desired way. Interestingly, if we had not needed the sum
+   of the squares and products, we could have obtained the sums, maxima,
+   and minima of the X's and Y's without a loop like this:
+
+  (setq xsum (+ \fjoin(&x)) ysum (+ \fjoin(&y)))
+  (setq xmax (max \fjoin(&x)) ymax (max \fjoin(&y)))
+  (setq xmin (min \fjoin(&x)) ymin (min \fjoin(&y)))
+
+   Any Kermit function that returns numbers or lists of numbers can be
+   included in an S-Expression as an operand.
+     _________________________________________________________________
+
+    9.9.2. Practical Fibonacci Series
+
+   The recursive Fibonacci example given previously is simple and
+   elegant, but not very useful since it causes memory occupation to grow
+   each time it calls itself, until eventually both physical memory and
+   disk swap space are filled and the program crashes. Even for small
+   arguments, like 17, execution time can be prohibitive:
+
+  (setq t1 \v(ftime))
+  (setq result (fibonacci 17))
+  (setq t2 (- \v(ftime) t1))
+  echo FIBONACCI(17) = \m(result): TIME = \ffpround(t2,3)
+
+   prints (on a certain rather slow computer):
+
+  FIBONACCI(17) = 1597: TIME = 5.861
+
+   Any recursive function can be recoded iteratively. The result is not
+   as pretty, but execution is far less expensive:
+
+    define FIBITER {
+        (if (== \%3 0) (\%2) (fibiter (+ \%1 \%2) \%1 (- \%3 1)))
+    }
+    define FIBONACCI {
+        (fibiter 1 0 \%1)
+    }
+
+   Here's the result on the same computer for the same argument of 17:
+
+  FIBONACCI(17) = 1597: TIME = 0.015
+
+   (47 times faster.) Execution time increases proportionally to the size
+   of the argument in the iterative case, whereas in the recursive case
+   it goes up geometrically, quickly reaching infinity.
+
+   [ [529]Top ] [ [530]Contents ] [ [531]C-Kermit Home ] [ [532]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.10. Differences from Algebraic Notation
+
+   In C-Kermit:
+
+     * Algebraic notation uses infix operators and normal rules of
+       operator precedence, with parentheses used to force exceptions to
+       the rules; many operations can be included in an expression.
+       S-Expressions use prefix operators with no intrinsic precedence;
+       each operation is enclosed in parentheses, and the arrangement of
+       parentheses determines precedence.
+     * Algebraic infix operators require two operands; S-Expression
+       prefix operators can accept a variable number of operands.
+     * You can use algebraic notation anywhere that C-Kermit accepts a
+       number, e.g. "echo \&a[((1+1)*2-1]", but you can use S-Expressions
+       only as top-level commands. You can, however, use either algebraic
+       or S-Expressions anywhere at all by enclosing them in \fevaluate()
+       or \fsexpression(), respectively.
+     * You can use any mixture of integer and floating-point numbers in
+       S-Expressions, but only integers are permitted in algebraic
+       expressions. Outside of S-Expressions, floating point arithmetic
+       is supported only by \ffp...() function calls.
+     * Operators and operands in S-Expressions must be separated by
+       spaces, e.g. "(+ a b)". Spaces are not required in algebraic
+       expressions: "((a+b)*c)".
+     * When assigning values to backslash variables (such as \%x or
+       \&a[2]) using SETQ or LET, you must double the backslash.
+
+   [ [533]Top ] [ [534]Contents ] [ [535]C-Kermit Home ] [ [536]Kermit
+   Home ]
+     _________________________________________________________________
+
+  9.11. Differences from Lisp
+
+     * Kermit has a lot of built-in operators not found in Lisp: ++, ^,
+       etc.
+     * Most dialects of real Lisp do not allow S-Expressions that don't
+       start with an operator, for example:
+  (a)
+       This expression can cause an error in Lisp (even if "a" has a
+       value), but is acceptable in Kermit, where it returns the value of
+       the variable "a". Similarly, (1) returns the value "1".
+     * In real Lisp, EVAL requires exactly one operand. In Kermit, it can
+       have 0, 1, 2, or more operands. It returns the value of the last
+       operand evaluated.
+     * Real Lisp SETQ and LET usually require an even number of operands.
+       Kermit allows an odd number, in which case the last (or only)
+       variable is undefined (i.e. deleted, destroyed).
+     * Kermit does not support ratios such as "7/8". Some Lisp dialects
+       accept ratios as numbers, and generate ratios when told to divide
+       two integers whose quotient is not a whole number; e.g. in Common
+       Lisp:
+  [13] USER(37): (/ (+ 1 2 3 4) 3)
+  10/3
+  [13] USER(38):
+     * The result of (/ 10 3) is 3.333.... Some Lisp dialects truncate
+       the result to 3 since both operands are integers, some don't; some
+       give the result as a ratio. C-Kermit always gives a floating point
+       result when there is a fractional part. If you want an integer
+       result, you can use TRUNCATE, FLOOR, or CEILING, e.g. (truncate (/
+       10 3)).
+     * There is currently no "bignum" support. Large numbers can be used
+       and large results generated, but (as noted in [537]Section 9.2)
+       they are accurate only to the precision of the underlying machine.
+       \v(math_precision) gives the machine precision as a number of
+       decimal digits, e.g. 16.
+     * Scientific notation for floating-point numbers is not supported.
+       If the magnitude of a number is greater than the precision of the
+       underlying hardware, the less-significant digits are shown but
+       their values are meaningless. If it the number is too small to be
+       represented internally, it is shown as "0.0".
+     * Many Lisp features are omitted: List processing (CAR, CDR, etc),
+       DEFUN, Lisp-specific control structures, and so on.
+
+   [ [538]Top ] [ [539]Contents ] [ [540]C-Kermit Home ] [ [541]Kermit
+   Home ]
+  __________________________________________________________________________
+
+10. FILE TRANSFER
+
+   New commands and switches:
+
+   SET TRANSFER REPORT { OFF, ON }
+          Enables or disables the (new) one-line message printed by
+          Kermit after a remote-mode file transfer to indicate the source
+          and destination file, complete with path, to let you know where
+          the file went.
+
+   SEND /TYPE:{TEXT,BINARY}
+          Sends only files of the given type (see [542]Section 4).
+
+   SEND /NOFOLLOWLINKS:
+          (UNIX only) Skip over symbolic links rather than following them
+          (default). This applies to wildcard and/or recursive SENDs; if
+          a single filename is given, and it happens to be a symbolic
+          link, the file it points to is sent.
+
+   SEND /FOLLOWLINKS:
+          (UNIX only) Follow (resolve) symbolic links. Watch out for
+          circular links, endless loops, etc.
+
+   SET SEND I-PACKETS { OFF, ON }
+          When sending commands to a Kermit server, this tells whether
+          command packets should be preceded by an I (information)
+          packet, which is used to synchronize parameters prior to
+          executing the command. Normally ON. The only reason to set this
+          OFF is for communicating with buggy Kermit servers that
+          misbehave when an I packet is sent to them. There is also a SET
+          RECEIVE I-PACKETS command, but presently it has no effect.
+
+   SET TRANSFER MESSAGE [ text ]
+          Sets an initial message to be shown in the Last Message field
+          of the fullscreen file-transfer display.
+
+   SET TRANSFER TRANSLATION { ON, OFF }
+          Inhibits or re-enables text-file transfer character-set
+          translation globally.
+
+   { SEND, MSEND, GET, RECEIVE } /TRANSPARENT
+          Inhibits character-set translation for this transfer only.
+
+   { GET, RECEIVE } /PIPES:{ON,OFF}
+          Overrides global TRANSFER PIPES setting for this transfer only;
+          ON allows incoming files with names like "!tar xf -" to be
+          opened as pipelines rather than regular files.
+
+   The following new "hot keys" are available when Kermit's file-transfer
+   display is visible:
+
+     D: Turn on debugging, open "debug.log" if not already open.
+     d: Turn off debugging but leave log open (if it was open).
+     T: Turn on debug-log timestamps.
+     t: Turn off debug-log timestamps.
+
+   Other improvements:
+     * SET FILE DOWNLOAD-DIRECTORY now works for external protocols (e.g.
+       sz/rz) too.
+     * Improved automatic per-file text/binary switching, described in
+       [543]Section 4.
+     * When sending a file group (e.g. "send *.*"), failure to open a
+       file is no longer fatal; now C-Kermit simply goes ahead to the
+       next file.
+     * Transaction log entries are now made for external protocols too.
+
+   [ [544]Top ] [ [545]Contents ] [ [546]C-Kermit Home ] [ [547]Kermit
+   Home ]
+  __________________________________________________________________________
+
+11. MODEMS AND DIALING
+
+   In C-Kermit 8.0, the default modem type for dialing has changed from
+   NONE (= DIRECT, meaning no modem) to GENERIC. This change should have
+   no impact on direct connections. For dialing, it means that, unless
+   you SET MODEM TYPE to a specific type, such as USROBOTICS or CONEXANT,
+   Kermit assumes:
+
+    1. The modem uses the Hayes AT command set.
+    2. The modem supports error correction, data compression, and
+       hardware flow control and is already configured to use them.
+
+   In fact, Kermit assumes the modem is completely configured, and
+   therefore does not send it an initialization string or any
+   configuration commands. Instead, it sends only the simplest and most
+   portable commands:
+
+     ATQ0V1          Give dial result codes.
+     ATDTnumber      Dial the number.
+
+   (or ATD or ATDP, as appropriate).
+
+   The new defaults work for direct connections and for most modern
+   modems on most platforms, and they work much faster than
+   "full-treatment" dialing. If the new defaults don't work for you, or
+   if you need to perform explicit modem configuations or interactions,
+   then set a specific modem type and use the SET MODEM and SET DIAL
+   commands as documented in Using C-Kermit.
+
+     WARNING: Don't use the generic modem on hosts that do not support
+     RTS/CTS flow control. If Xon/Xoff is in use on the serial port,
+     you'll need to select a particular modem type so Kermit knows what
+     command to give it to enable Xon/Xoff flow control between itself
+     and your serial port.
+
+   The following new modem types were added in C-Kermit 8.0:
+
+     lucent:          Lucent Venus chipset
+     pctel:           PCTel V.90 chipset
+     conexant:        Conexant (ex-Rockwell) modem family
+     zoom-v32bis:     New name for "Zoom"
+     zoom-v34         Zoom V.34
+     zoom-v90         Zoom V.90 56K
+     zoom-v92:        Zoom V.92 with V.44 data compression
+     zoltrix-v34:     New name for "zoltrix"
+     zoltrix-hsp-v90: Synonym for PCTel
+     zoltrix-hcf-v90: Synonym for ITU-T-V250
+     smartlink-v90:   Synonym for usrobotics (same chipset)
+     acer-v90:        Synonym for Rockwell-v90
+
+   New DIAL-related variables:
+
+     \v(dm_hf):  Dial modifier: Wait for Hook-Flash.
+     \v(dm_wb):  Dial modifier: Wait for Bong.
+
+   Finally, if dialing fails, Kermit now prints a context-sensitive hint
+   suggesting possible reasons and remedies.
+
+   Added in C-Kermit 8.0.201:   Rudimentary support for Caller ID, for
+   use with the ANSWER command. If the modem reports Caller ID
+   information, Kermit stores it in variables that you can access after
+   the call is answered:
+
+  \v(callid_date)   The date of the call
+  \v(callid_time)   The time of the call
+  \v(callid_name)   The name of the caller
+  \v(callid_nmbr)   The telephone number of the caller
+  \v(callid_mesg)   A message
+
+   The format of these items depends on the originating and answering
+   phone companies and the modems and their configuration.
+
+   Not very many modems support Caller ID, and those that do (a) tend to
+   have it disabled by default, and (b) use different commands to enable
+   it. A quick survey shows of some current models shows:
+
+   - USR V.90:      No
+   - ITU-T V.250:   No
+   - Lucent Venus:  No
+   - Diamond Supra: #CID=1
+   - Rockwell 56K:  #CID=1
+   - PCTEL:         #CID=1
+   - Zoltrix:       +VCID=1
+   - Conexant:      +VCID=1
+
+   To use Kermit's Caller ID feature, you have to set the modem to wait
+   for at least two rings before answering, and you have to give the
+   command to enable Caller ID; for example (after choosing a modem with
+   SET MODEM TYPE):
+
+  set modem command autoanswer on ATS0=2#CID=1\{13}
+  set modem command autoanswer on ATS0=2+VCID=1\{13}
+
+   These commands can be undone with:
+
+  set modem command autoanswer on ATS0=1#CID=0\{13}
+  set modem command autoanswer on ATS0=1+VCID=0\{13}
+
+   Kermit presently has no built-in knowledge of the Caller ID
+   capabilities or commands of the modems in its database.
+
+   Since the variables can be accessed only after the call is answered,
+   the only way to refuse a call is to answer it, inspect the variables,
+   and then hang it up if desired.
+
+   [ [548]Top ] [ [549]Contents ] [ [550]C-Kermit Home ] [ [551]Kermit
+   Home ]
+  __________________________________________________________________________
+
+12. TERMINAL CONNECTION
+
+   Now that 7-bit connections are no longer the norm, the default
+   terminal bytesize (also called "data size" or "word size") in C-Kermit
+   8.0 is 8 bits, rather than 7 bits as it was in C-Kermit 7.0 and
+   earlier:
+
+   SET ESCAPE character
+          This command, which specifies your CONNECT-mode escape
+          character, allows you to specify any ASCII control character in
+          a variety of formats. C-Kermit 8.0.201 now also lets you
+          specify any 8-bit value, 128-255, as the escape character. In
+          the SET ESCAPE command, you can type the 8-bit character
+          literally or you can enter its numeric code. Here are examples
+          that you can enter from a terminal or console that uses the ISO
+          Latin-1 character set:
+
+  C-Kermit> set escape Ã
+  C-Kermit> set escape 195
+  C-Kermit> show escape
+   Escape character: Code 195 (Ã): enabled
+  C-Kermit>
+
+          Both of these commands set the escape character value to 195
+          (decimal), which happens to be uppercase letter A with Tilde in
+          Latin-1. SHOW ESCAPE and SHOW TERMINAL show the value, as does
+          the CONNECT message.
+
+   SET TERMINAL AUTODOWNLOAD ERROR { STOP, CONTINUE }
+          When Kermit has a terminal connection to another computer, and
+          a file transfer is initiated automatically because a Kermit
+          packet was received in CONNECT mode (i.e. in the terminal
+          screen), this command tells what Kermit should do if the
+          transfer fails. The default is to STOP, which leaves Kermit in
+          command mode with its file-transfer display showing, so you can
+          see that the transfer failed and why. If you SET TERMINAL
+          AUTODOWNLOAD ERROR CONTINUE, this causes Kermit to return
+          automatically to its terminal screen (i.e. resume its CONNECT
+          session) as if the transfer had succeeded; this can be
+          desirable if the entire session is under control of a
+          host-based script.
+
+   SET TERMINAL BYTESIZE { 7, 8 }
+          The byte size to use during CONNECT and INPUT command
+          execution, which can be more restrictive than the bytesize
+          implied by the current PARITY setting, but not less
+          restrictive. In C-Kermit 7.0 and earlier, the terminal bytesize
+          was 7 by default to protect against the likelihood that parity
+          was in use on the connection without the user's knowledge. When
+          the terminal bytesize is 8 (as it is in C-Kermit 8.0 and
+          later), the user will see garbage in this (increasingly
+          unlikely) situation. Note that 8 data bits are required for
+          most character sets other than ASCII: Latin-1, UTF-8, and so
+          on.
+
+   A new command has been added to produce timestamped session logs:
+
+   SET TERMINAL SESSION-LOG TIMESTAMPED-TEXT
+          Records the terminal session in text mode (like SET TERMINAL
+          SESSION-LOG TEXT) but adds a timestamp at the beginning of each
+          line. The timestamp format is hh:mm:ss.nnn, and indicates the
+          time at which the first character of the line appeared.
+
+   In most UNIX versions (those built with the select()-capable CONNECT
+   module -- pretty much all the ones that have or could have TELNET
+   included), an idle timeout feature has been added:
+
+   SET TERMINAL IDLE-TIMEOUT number
+          If the number is not 0, then Kermit is to take an action when
+          the given amount of time passes with no activity during CONNECT
+          mode. If the number is positive it is the maximum number of
+          idle seconds; if number is negative it represents milliseconds
+          (thousandths of seconds). If 0 is given as the number, there
+          are no idle timeouts. Synonym: SET TERMINAL IDLE-LIMIT.
+
+   SET TERMINAL IDLE-ACTION { RETURN, HANGUP, EXIT, OUTPUT [ string ] }
+          The action to be taken upon an idle timeout in CONNECT mode.
+          RETURN to the prompt, HANGUP the connection, EXIT from Kermit,
+          or OUTPUT the given string (if no string is given, a NUL (ASCII
+          0) character is sent).
+
+   SET TERMINAL IDLE-ACTION { TELNET-NOP, TELNET-AYT }
+          Actions that can be selected on Telnet connections only, that
+          might be useful if idle limits are enforced by the Telnet
+          server or in the TCP/IP protocol: TELNET-NOP sends a "NO
+          Operation" (do-nothing) command, which causes no response from
+          the server; TELNET-AYT sends an "Are You There" message to the
+          server, which should make the server send back a message.
+          Neither of these actions interferes with your remote session.
+
+   SET TERMINAL IDLE-ACTION is useful for connections to hosts or
+   services that automatically log you out after a certain amount of idle
+   time, e.g.:
+
+  set term idle-timeout 300
+  set term idle-action output \32
+
+   sends a space (as if you had pressed the space bar) every 300 seconds
+   (five minutes) while there is no activity (32 is the ASCII code for
+   space).
+
+   When C-Kermit returns from CONNECT to command mode, the reason for the
+   transition is given in a new variable, \v(cx_status):
+
+      0  No CONNECT command given yet.
+      1  User escaped back manually.
+      2  A trigger string was encountered.
+      3  IKSD entered server mode.
+      4  Application Program Command received from host.
+      5  Idle timeout.
+      6  Telnet protocol error.
+      7  Keystroke macro.
+      8  Time limit exceeded.
+    100  Internal error.
+    101  Carrier required by not detected.
+    102  I/O error on connection.
+    103  Disconnected by host.
+    104  Disconnected by user.
+    105  Session limit exceeded.
+    106  Rejected due to Telnet policy.
+    107  Received kill signal.
+
+   Values 100 and above indicate there is no connection.
+
+   [ [552]Top ] [ [553]Contents ] [ [554]C-Kermit Home ] [ [555]Kermit
+   Home ]
+  __________________________________________________________________________
+
+13. CHARACTER SETS
+
+   See the section on [556]file scanning above, and the section on
+   character-set conversion in [557]FTP. Also:
+
+     * True support for CP1252 (rather than treating it as Latin-1).
+     * Proper handling of C1 values when converting ISO 8-bit text to
+       UTF-8.
+     * TYPE /CHARACTER-SET: /TRANSLATE-TO: allows specific translations.
+     * The TRANSLATE command now works on multiple files.
+     * K_CHARSET environment variable to set the file character-set.
+     * SET TRANSFER TRANSLATION OFF.
+     * FTP client character-set translation ([558]Section 3.7).
+
+   [ [559]Top ] [ [560]Contents ] [ [561]C-Kermit Home ] [ [562]Kermit
+   Home ]
+  __________________________________________________________________________
+
+14. DIALOUT FROM TELNET TERMINAL SERVERS
+
+   For years, C-Kermit has supported dialing out from Telnet modem
+   servers (also called reverse terminal servers or access servers), but
+   until now there was no way for Kermit to control the communication
+   parameters (speed, parity, etc) on the serial port of the terminal
+   server; it had to use whatever was there.
+
+   But now, if you make a connection to a server that supports the Telnet
+   Com Port Control Option, [563]RFC 2217, you have the same degree of
+   control as you would have over a serial port on the computer where
+   Kermit is running: SET SPEED, SET FLOW, SET PARITY, SET STOP-BITS,
+   SHOW COMM, WAIT, SET CARRIER-WATCH, the modem-signal variables,
+   sending Break, and so on, apply to the connection between the terminal
+   server and the modem.
+
+   For example, using a Cisco Access Server 2509, where specifying a TCP
+   port in the 6000's selects a serial port that can be used for dialing
+   out:
+
+  set host xxx 6001      ; xxx is the IP hostname or address of the server
+  (log in if necessary)  ; With a script or by hand
+  set modem type usr     ; Tell Kermit what kind of modem it has
+  set speed 57600        ; This affects the server's port
+  set flow rts/cts       ; Ditto
+  dial 7654321
+
+   The modem server might or might not require a login sequence. It might
+   also allow for automatic authentication, e.g. via Kerberos tickets.
+   NOTE: If the modem server requires a login sequence, then REDIAL might
+   not work as expected.
+
+   When you have a Telnet Com Port connection, your SET SPEED and SET
+   FLOW options change automatically to reflect the capabilities of the
+   server, rather than those of your local computer.
+
+   See the configuration manual for your server for additional
+   information. For example, how to set up the server to drop the Telnet
+   connection automatically when the telephone call is hung up (e.g.
+   "autohangup" on Cisco models).
+
+   For a Linux-based Telnet Com-Port server, click the Srdird link:
+
+   [ [564]Top ] [ [565]Contents ] [ [566]Sredird ] [ [567]C-Kermit Home ]
+   [ [568]Kermit Home ]
+  __________________________________________________________________________
+
+15. COPING WITH BROKEN KERMIT PARTNERS
+
+   There are lots of faulty Kermit protocol implementations out there,
+   found mainly in 3rd-party products ranging from communications
+   software packages to file-transfer functions imbedded within devices.
+   This topic is covered [569]HERE for C-Kermit 7.0, but C-Kermit 8.0
+   adds some additional tricks.
+
+   SET ATTRIBUTE RECORD-FORMAT { ON, OFF }
+          Allows control of the Kermit's Record-Format attribute. Set
+          this to OFF in case incoming file are refused due to unknown or
+          invalid record formats if you want to accept the file anyway.
+
+   SET SEND I-PACKETS { ON, OFF }
+          A Kermit server is supposed to accept I-packets; this is how
+          the client lets the server know its capabilities and
+          preferences before sending a command. Apparently there is at
+          least one Kermit server implementation that does not accept
+          I-packets, and does not properly respond with an Error packet
+          if it gets one. To get around such situations in C-Kermit 8.0,
+          you can use SET SEND I-PACKETS OFF to inhibit the sending of I
+          packets. In this case, the client must be able to adjust to the
+          server's configuration, rather than the other way around as we
+          are used to.
+
+   SET PROTOCOL KERMIT {} {} {}
+          C-Kermit 6.0 and later automatically send "autoupload" and
+          "autodownload" commands when in local mode and you give a file
+          transfer command. For example, if you tell kermit to "send
+          oofa.txt", Kermit sends "kermit -r" and a carriage return, in
+          case you had forgotten to start Kermit on the far end and told
+          it to receive a file. If a Kermit program had already been
+          started on the far end, it should harmlessly absorb this
+          string. However, some Kermit programs violate the Kermit
+          protocol definition and treat such strings as Kermit packets
+          even though they are not. In such cases, give this command to
+          set the Kermit protocol autoupload and download strings to
+          nothing, which tells Kermit not to send them. (This is not a
+          new feature, but it was not previously included in the "Coping"
+          section of the documentation.)
+
+   [ [570]Top ] [ [571]Contents ] [ [572]C-Kermit Home ] [ [573]Kermit
+   Home ]
+  __________________________________________________________________________
+
+16. NEW COMMAND-LINE OPTIONS
+
+   kermit -h Now prints a complete listing of its command-line options,
+   rather than an abbreviated list squeezed into a 24x80 space.
+
+   -dd              Debug, like -d but adds timestamps
+   --version  Shows C-Kermit version number.
+   --noperms  Equivalent to SET ATTRIBUTE PROTECTION OFF.
+
+   Kermit now accepts a selection of URLs (Universal Resource Locators)
+   as its first command-line argument. These are:
+
+   telnet:hostname
+          Makes a Telnet connection to the given host (IP hostname or
+          address).
+
+   ftp://[user[:password]@]hostname[/path...]
+          Makes an FTP connection to the given host (IP hostname or
+          address). If a username is given, Kermit tries to log you in;
+          if a password is given, it is used; if not, you are prompted
+          for one. If no username is given, an anonymous login is
+          performed. If a pathname is included, Kermit tries to GET the
+          given file. See [574]Section 3.1.3 for details.
+
+   ftps://[user[:password]@]hostname[/path...]
+          Makes a secure FTP connection over SSL.
+
+   telnets://[user[:password]@]hostname
+          Makes a secure Telnet connection over SSL.
+
+   kermit://[user[:password]@]hostname[/path...]
+          Makes a connection to an [575]Internet Kermit Server.
+
+   http://[user[:password]@]hostname[/path...]
+          Makes a connection to Web server.
+
+   https://[user[:password]@]hostname[/path...]
+          Makes a connection to secure Web server.
+
+   [ [576]Top ] [ [577]Contents ] [ [578]C-Kermit Home ] [ [579]Kermit
+   Home ]
+  __________________________________________________________________________
+
+17. LOGS
+
+   In C-Kermit 8.0, we make an effort to keep passwords out of the debug
+   log. This can never be 100% effective, but it's better than before,
+   when there were no precautions at all. Whenever Kermit knows it's
+   prompting for, parsing, or transmitting a password, it temporarily
+   turns off logging and then turns it back on afterwards. This keeps the
+   debug log password-free in most common cases, but there can be no
+   guarantees.
+
+   As noted elsewhere, the new "-dd" command-line option selects a
+   timestamped debug log (equivalent to "set debug timestamps on", "log
+   debug debug.log").
+
+   C-Kermit 8.0 also supports a new timestamped session log via "set
+   session-log timestamped-text", "log session".
+
+   There have been requests for other kinds of logs, for example a
+   command log. These might be added at some point. One person wanted to
+   be able to log commands with timestamps, but only commands issued at
+   the prompt, not commands from files or macros, and also wanted a
+   header line at the beginning showing the date, user, and host. This
+   can be done as follows:
+
+  .filename := \v(home)commands.log  ; (for example)
+  fopen /write \%c \m(filename)
+  if success {
+      fwrite /line \%c \v(date): User=\v(user) Host=\v(host)
+      fclose \%c
+      set debug timestamps on
+      log debug {| grep "CMD(P)" >> \m(filename)} append
+  }
+
+   [ [580]Top ] [ [581]Contents ] [ [582]C-Kermit Home ] [ [583]Kermit
+   Home ]
+     _________________________________________________________________
+
+   C-Kermit 8.0 Update Notes / [584]The Kermit Project / Columbia
+   University / 15 Dec 2003
+
+References
+
+   1. http://www.columbia.edu/kermit/ckermit80.html#contents
+   2. http://www.columbia.edu/kermit/ckermit.html
+   3. http://www.columbia.edu/kermit/index.html
+   4. http://www.columbia.edu/kermit/ckermit80.html
+   5. mailto:kermit-support@columbia.edu
+   6. http://www.columbia.edu/kermit/
+   7. http://www.kermit-project.org/
+   8. http://www.columbia.nyc.ny.us/kermit/
+   9. ftp://kermit.columbia.edu/kermit/f/COPYING.TXT
+  10. ftp://kermit.columbia.edu/kermit/f/ckcmai.c
+  11. http://www.columbia.edu/kermit/ckermit80.html#xv
+  12. http://www.columbia.edu/kermit/ck60manual.html
+  13. http://www.columbia.edu/kermit/ckermi70.html
+  14. ftp://kermit.columbia.edu/kermit/f/ckermit70.txt
+  15. http://www.columbia.edu/kermit/ckututor.html
+  16. ftp://kermit.columbia.edu/kermit/f/ckuker.nr
+  17. http://www.columbia.edu/kermit/security.htm
+  18. http://www.columbia.edu/kermit/telnet.htm
+  19. http://www.columbia.edu/kermit/ftpscripts.html
+  20. http://www.columbia.edu/kermit/ckcbwr.html
+  21. ftp://kermit.columbia.edu/kermit/f/ckcbwr.txt
+  22. http://www.columbia.edu/kermit/ckubwr.html
+  23. ftp://kermit.columbia.edu/kermit/f/ckubwr.txt
+  24. http://www.columbia.edu/kermit/ckvbwr.html
+  25. ftp://kermit.columbia.edu/kermit/f/ckvbwr.txt
+  26. http://www.columbia.edu/kermit/ckuins.html
+  27. ftp://kermit.columbia.edu/kermit/f/ckuins.txt
+  28. http://www.columbia.edu/kermit/ckvins.html
+  29. ftp://kermit.columbia.edu/kermit/f/ckvins.txt
+  30. http://www.columbia.edu/kermit/ckccfg.html
+  31. ftp://kermit.columbia.edu/kermit/f/ckccfg.txt
+  32. http://www.columbia.edu/kermit/ckcplm.html
+  33. ftp://kermit.columbia.edu/kermit/f/ckcplm.txt
+  34. http://www.columbia.edu/kermit/iksd.html
+  35. http://www.columbia.edu/kermit/skermit.html
+  36. http://www.columbia.edu/kermit/ckermit80.html#top
+  37. http://www.columbia.edu/kermit/ckermit.html
+  38. http://www.columbia.edu/kermit/index.html
+  39. http://www.columbia.edu/kermit/ckermit80.html#x0
+  40. http://www.columbia.edu/kermit/ckermit80.html#x1
+  41. http://www.columbia.edu/kermit/ckermit80.html#x2
+  42. http://www.columbia.edu/kermit/ckermit80.html#x2.1
+  43. http://www.columbia.edu/kermit/ckermit80.html#x2.2
+  44. http://www.columbia.edu/kermit/ckermit80.html#x2.2.1
+  45. http://www.columbia.edu/kermit/ckermit80.html#x2.2.2
+  46. http://www.columbia.edu/kermit/ckermit80.html#x2.2.3
+  47. http://www.columbia.edu/kermit/ckermit80.html#x2.2.4
+  48. http://www.columbia.edu/kermit/ckermit80.html#x2.2.5
+  49. http://www.columbia.edu/kermit/ckermit80.html#x2.2.6
+  50. http://www.columbia.edu/kermit/ckermit80.html#x3
+  51. http://www.columbia.edu/kermit/ckermit80.html#x3.1
+  52. http://www.columbia.edu/kermit/ckermit80.html#x3.1.1
+  53. http://www.columbia.edu/kermit/ckermit80.html#x3.1.2
+  54. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+  55. http://www.columbia.edu/kermit/ckermit80.html#x3.1.4
+  56. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+  57. http://www.columbia.edu/kermit/ckermit80.html#x3.3
+  58. http://www.columbia.edu/kermit/ckermit80.html#x3.4
+  59. http://www.columbia.edu/kermit/ckermit80.html#x3.5
+  60. http://www.columbia.edu/kermit/ckermit80.html#x3.5.1
+  61. http://www.columbia.edu/kermit/ckermit80.html#x3.5.2
+  62. http://www.columbia.edu/kermit/ckermit80.html#x3.5.3
+  63. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+  64. http://www.columbia.edu/kermit/ckermit80.html#x3.6.1
+  65. http://www.columbia.edu/kermit/ckermit80.html#x3.6.2
+  66. http://www.columbia.edu/kermit/ckermit80.html#x3.6.3
+  67. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+  68. http://www.columbia.edu/kermit/ckermit80.html#x3.7.1
+  69. http://www.columbia.edu/kermit/ckermit80.html#x3.7.2
+  70. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+  71. http://www.columbia.edu/kermit/ckermit80.html#x3.9
+  72. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+  73. http://www.columbia.edu/kermit/ckermit80.html#x3.10.1
+  74. http://www.columbia.edu/kermit/ckermit80.html#x3.10.2
+  75. http://www.columbia.edu/kermit/ckermit80.html#x3.10.3
+  76. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+  77. http://www.columbia.edu/kermit/ckermit80.html#x4
+  78. http://www.columbia.edu/kermit/ckermit80.html#x5
+  79. http://www.columbia.edu/kermit/ckermit80.html#x6
+  80. http://www.columbia.edu/kermit/ckermit80.html#x6.1
+  81. http://www.columbia.edu/kermit/ckermit80.html#x6.2
+  82. http://www.columbia.edu/kermit/ckermit80.html#x6.3
+  83. http://www.columbia.edu/kermit/ckermit80.html#x6.4
+  84. http://www.columbia.edu/kermit/ckermit80.html#x6.5
+  85. http://www.columbia.edu/kermit/ckermit80.html#x6.6
+  86. http://www.columbia.edu/kermit/ckermit80.html#x7
+  87. http://www.columbia.edu/kermit/ckermit80.html#x8
+  88. http://www.columbia.edu/kermit/ckermit80.html#x8.1
+  89. http://www.columbia.edu/kermit/ckermit80.html#x8.2
+  90. http://www.columbia.edu/kermit/ckermit80.html#x8.3
+  91. http://www.columbia.edu/kermit/ckermit80.html#x8.4
+  92. http://www.columbia.edu/kermit/ckermit80.html#x8.5
+  93. http://www.columbia.edu/kermit/ckermit80.html#x8.6
+  94. http://www.columbia.edu/kermit/ckermit80.html#x8.7
+  95. http://www.columbia.edu/kermit/ckermit80.html#x8.8
+  96. http://www.columbia.edu/kermit/ckermit80.html#x8.9
+  97. http://www.columbia.edu/kermit/ckermit80.html#x8.10
+  98. http://www.columbia.edu/kermit/ckermit80.html#x8.11
+  99. http://www.columbia.edu/kermit/ckermit80.html#x8.12
+ 100. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 101. http://www.columbia.edu/kermit/ckermit80.html#x8.14
+ 102. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 103. http://www.columbia.edu/kermit/ckermit80.html#x9.1
+ 104. http://www.columbia.edu/kermit/ckermit80.html#x9.2
+ 105. http://www.columbia.edu/kermit/ckermit80.html#x9.3
+ 106. http://www.columbia.edu/kermit/ckermit80.html#x9.4
+ 107. http://www.columbia.edu/kermit/ckermit80.html#x9.5
+ 108. http://www.columbia.edu/kermit/ckermit80.html#x9.6
+ 109. http://www.columbia.edu/kermit/ckermit80.html#x9.7
+ 110. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 111. http://www.columbia.edu/kermit/ckermit80.html#x9.9
+ 112. http://www.columbia.edu/kermit/ckermit80.html#x9.10
+ 113. http://www.columbia.edu/kermit/ckermit80.html#x9.11
+ 114. http://www.columbia.edu/kermit/ckermit80.html#x10
+ 115. http://www.columbia.edu/kermit/ckermit80.html#x11
+ 116. http://www.columbia.edu/kermit/ckermit80.html#x12
+ 117. http://www.columbia.edu/kermit/ckermit80.html#x13
+ 118. http://www.columbia.edu/kermit/ckermit80.html#x14
+ 119. http://www.columbia.edu/kermit/ckermit80.html#x15
+ 120. http://www.columbia.edu/kermit/ckermit80.html#x16
+ 121. http://www.columbia.edu/kermit/ckermit80.html#x17
+ 122. http://www.columbia.edu/kermit/ckermit80.html#top
+ 123. http://www.columbia.edu/kermit/ckermit.html
+ 124. http://www.columbia.edu/kermit/index.html
+ 125. http://www.columbia.edu/kermit/ckuins.html#x5
+ 126. http://www.columbia.edu/kermit/ckuins.html
+ 127. http://www.columbia.edu/kermit/ckermit80.html#x5
+ 128. http://www.columbia.edu/kermit/ckermit80.html#x2.2
+ 129. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 130. http://www.columbia.edu/kermit/ckermit80.html#x15
+ 131. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 132. http://www.columbia.edu/kermit/ckermit80.html#ftpdates
+ 133. http://www.columbia.edu/kermit/ckermit80.html#ftpcheck
+ 134. http://www.columbia.edu/kermit/ckermit80.html#ftpnamelist
+ 135. http://www.columbia.edu/kermit/ckermit80.html#srvrename
+ 136. http://www.columbia.edu/kermit/ckermit80.html#ftpvdir
+ 137. http://www.columbia.edu/kermit/ckermit80.html#setftptype
+ 138. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 139. http://www.columbia.edu/kermit/ckermit80.html#x15
+ 140. http://www.columbia.edu/kermit/ckermit80.html#x8.7
+ 141. http://www.columbia.edu/kermit/ckermit80.html#x2.1
+ 142. http://www.columbia.edu/kermit/ckermit80.html#x2.2
+ 143. http://www.columbia.edu/kermit/ckermit80.html#x8.14
+ 144. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 145. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 146. http://www.columbia.edu/kermit/ckututor.html
+ 147. http://www.columbia.edu/kermit/ckuins.html
+ 148. http://www.columbia.edu/kermit/skermit.html
+ 149. http://www.columbia.edu/kermit/ckermit80.html#setlocus
+ 150. http://www.columbia.edu/kermit/ckermit80.html#lcommands
+ 151. http://www.columbia.edu/kermit/ckermit80.html#ftpuser
+ 152. http://www.columbia.edu/kermit/ckermit80.html#showvar
+ 153. http://www.columbia.edu/kermit/ckermit80.html#callerid
+ 154. http://www.columbia.edu/kermit/ckermit80.html#x6.6
+ 155. http://www.columbia.edu/kermit/ckermit80.html#x0
+ 156. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 157. http://www.columbia.edu/kermit/ckermit80.html#top
+ 158. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 159. http://www.columbia.edu/kermit/ckermit.html
+ 160. http://www.columbia.edu/kermit/index.html
+ 161. http://www.columbia.edu/kermit/ckermit80.html#x0
+ 162. http://www.columbia.edu/kermit/ckermit80.html#top
+ 163. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 164. http://www.columbia.edu/kermit/ckermit.html
+ 165. http://www.columbia.edu/kermit/index.html
+ 166. http://www.columbia.edu/kermit/k95.html
+ 167. http://www.columbia.edu/kermit/sshclient.html
+ 168. http://www.columbia.edu/kermit/skermit.html
+ 169. http://www.columbia.edu/kermit/skermit.html
+ 170. http://www.columbia.edu/kermit/sshclien.htm
+ 171. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 172. ftp://ftp.isi.edu/in-notes/rfc1738.txt
+ 173. http://www.columbia.edu/kermit/ckermit80.html#x2.2.2
+ 174. http://www.columbia.edu/kermit/ckermit80.html#x2.2.1
+ 175. ftp://ftp.isi.edu/in-notes/rfc2396.txt
+ 176. ftp://ftp.isi.edu/in-notes/rfc2616.txt
+ 177. http://www.columbia.edu/kermit/ckermit80.html#x2.2.3
+ 178. ftp://ftp.isi.edu/in-notes/rfc2616.txt
+ 179. http://www.columbia.edu/kermit/ckermit80.html#x8.13.7
+ 180. http://www.columbia.edu/kermit/security.htm#x5.4
+ 181. http://www.columbia.edu/kermit/security.htm#x15
+ 182. http://www.columbia.edu/kermit/security.htm#x6.2
+ 183. http://www.columbia.edu/kermit/security.html
+ 184. http://www.columbia.edu/kermit/ckermit80.html#x16
+ 185. http://www.columbia.edu/kermit/ckermit80.html#top
+ 186. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 187. http://www.columbia.edu/kermit/ckermit.html
+ 188. http://www.columbia.edu/kermit/index.html
+ 189. http://www.columbia.edu/kermit/ckermit80.html#x3.1
+ 190. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 191. http://www.columbia.edu/kermit/ckermit80.html#x3.3
+ 192. http://www.columbia.edu/kermit/ckermit80.html#x3.4
+ 193. http://www.columbia.edu/kermit/ckermit80.html#x3.5
+ 194. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 195. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 196. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 197. http://www.columbia.edu/kermit/ckermit80.html#x3.9
+ 198. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+ 199. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 200. http://www.columbia.edu/kermit/security.htm
+ 201. http://www.columbia.edu/kermit/security.htm#servers
+ 202. http://www.columbia.edu/kermit/ckcsets.html
+ 203. http://www.columbia.edu/kermit/unicode.html
+ 204. http://www.columbia.edu/kermit/ckermi70.htm#x1.5.4
+ 205. http://www.columbia.edu/kermit/case10.html
+ 206. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 207. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 208. http://www.columbia.edu/kermit/ftpscripts.html
+ 209. http://www.columbia.edu/kermit/ckermit80.html#top
+ 210. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 211. http://www.columbia.edu/kermit/ftpclient.html
+ 212. http://www.columbia.edu/kermit/ftpscripts.html
+ 213. http://www.columbia.edu/kermit/ckermit.html
+ 214. http://www.columbia.edu/kermit/index.html
+ 215. http://www.columbia.edu/kermit/ckermit80.html#x3.1.1
+ 216. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+ 217. http://www.columbia.edu/kermit/ckermit80.html#x3.1.4
+ 218. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+ 219. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+ 220. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 221. http://www.columbia.edu/kermit/ckermit80.html#x3.5
+ 222. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 223. http://www.columbia.edu/kermit/ftpscripts.html
+ 224. http://www.columbia.edu/kermit/ckb2.htm
+ 225. http://www.columbia.edu/kermit/ckermit80.html#ftpautolog
+ 226. http://www.columbia.edu/kermit/ckermit80.html#ftpuser
+ 227. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 228. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 229. http://www.columbia.edu/kermit/ckermit80.html#top
+ 230. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 231. http://www.columbia.edu/kermit/ckermit.html
+ 232. http://www.columbia.edu/kermit/index.html
+ 233. http://www.columbia.edu/kermit/ibm_ie.html
+ 234. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+ 235. http://www.columbia.edu/kermit/ckermit80.html#top
+ 236. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 237. http://www.columbia.edu/kermit/ckermit.html
+ 238. http://www.columbia.edu/kermit/index.html
+ 239. http://www.columbia.edu/kermit/ck60manual.html
+ 240. http://www.columbia.edu/kermit/ckermit70.html#x4.17
+ 241. http://www.columbia.edu/kermit/ckermit70.html
+ 242. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 243. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 244. http://www.columbia.edu/kermit/ckermit80.html#x3.1.4
+ 245. http://www.columbia.edu/kermit/security.html
+ 246. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 247. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 248. http://www.columbia.edu/kermit/ckermit80.html#x8.13.4
+ 249. http://www.columbia.edu/kermit/ckermit80.html#permswitch
+ 250. http://www.columbia.edu/kermit/ckermit80.html#ftpchmod
+ 251. http://www.columbia.edu/kermit/ckermit80.html#x3.6.2
+ 252. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 253. http://www.columbia.edu/kermit/ckermit80.html#top
+ 254. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 255. http://www.columbia.edu/kermit/ckermit.html
+ 256. http://www.columbia.edu/kermit/index.html
+ 257. http://www.columbia.edu/kermit/ckermit80.html#x7
+ 258. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 259. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 260. http://www.columbia.edu/kermit/ckb2.htm
+ 261. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+ 262. http://www.columbia.edu/kermit/ckermit80.html#x3.10
+ 263. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 264. http://www.columbia.edu/kermit/ckermit80.html#setftptype
+ 265. http://www.columbia.edu/kermit/ckermit80.html#top
+ 266. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 267. http://www.columbia.edu/kermit/ckermit.html
+ 268. http://www.columbia.edu/kermit/index.html
+ 269. http://www.columbia.edu/kermit/ckermit70.html#x4.9
+ 270. http://www.columbia.edu/kermit/ckermit80.html#x3.5.1
+ 271. http://www.columbia.edu/kermit/ckermit80.html#erroraction
+ 272. http://www.columbia.edu/kermit/ckermit70.html#x1.5
+ 273. http://www.columbia.edu/kermit/ckermit70.html#x4.7
+ 274. http://www.columbia.edu/kermit/ckermit70.html#x1.6
+ 275. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 276. http://www.columbia.edu/kermit/ckermi70.htm#x1.5.4
+ 277. http://www.columbia.edu/kermit/ckermi70.htm
+ 278. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 279. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 280. http://www.columbia.edu/kermit/ckermit80.html#x3.5.2
+ 281. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 282. http://www.columbia.edu/kermit/ckermit80.html#erroraction
+ 283. http://www.columbia.edu/kermit/ckermit80.html#x3.5.2
+ 284. http://www.columbia.edu/kermit/ckermit80.html#erroraction
+ 285. http://www.columbia.edu/kermit/ckermit80.html#ftpfilenames
+ 286. http://www.columbia.edu/kermit/ckermit80.html#ftpperms
+ 287. http://www.columbia.edu/kermit/ckermit80.html#ftpunique
+ 288. http://www.columbia.edu/kermit/ckermit80.html#ftpfilenames
+ 289. http://www.columbia.edu/kermit/ckermit80.html#note_utc
+ 290. http://www.columbia.edu/kermit/ckermit80.html#note_date
+ 291. http://www.columbia.edu/kermit/ckermit80.html#x3.6
+ 292. http://www.boulder.nist.gov/timefreq/faq/faq.htm#10:
+ 293. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 294. http://www.columbia.edu/kermit/ckermit80.html#top
+ 295. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 296. http://www.columbia.edu/kermit/ckermit.html
+ 297. http://www.columbia.edu/kermit/index.html
+ 298. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 299. http://www.columbia.edu/kermit/ckermi70.htm#x4.3
+ 300. http://www.columbia.edu/kermit/ckermit70.html
+ 301. http://www.columbia.edu/kermit/ckermit80.html#x5
+ 302. http://www.columbia.edu/kermit/ckermit80.html#x3.6.3
+ 303. http://www.columbia.edu/kermit/ckermit80.html#ftpfilenames
+ 304. http://www.columbia.edu/kermit/ckermi70.htm#x4.1
+ 305. http://www.columbia.edu/kermit/ckermi70.htm#x4.2.2
+ 306. http://www.columbia.edu/kermit/ckermi70.htm#x1.5.4
+ 307. http://www.columbia.edu/kermit/ckermit80.html#x3.6.2
+ 308. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 309. http://www.columbia.edu/kermit/ckermit80.html#x3.11
+ 310. http://www.columbia.edu/kermit/ckermit80.html#srvrename
+ 311. http://www.columbia.edu/kermit/ckermi70.htm#x4.1
+ 312. http://www.columbia.edu/kermit/ckermi70.htm
+ 313. http://www.columbia.edu/kermit/ckb2.htm
+ 314. http://www.columbia.edu/kermit/ckermit80.html#ftpfilenames
+ 315. http://www.columbia.edu/kermit/ckermit80.html#x3.5.3
+ 316. http://www.proftpd.net/
+ 317. http://www.columbia.edu/kermit/ckermit80.html#top
+ 318. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 319. http://www.columbia.edu/kermit/ckermit.html
+ 320. http://www.columbia.edu/kermit/index.html
+ 321. http://www.columbia.edu/kermit/ckb2.htm
+ 322. http://www.columbia.edu/kermit/ckcsets.html
+ 323. http://www.columbia.edu/kermit/unicode.html
+ 324. http://www.columbia.edu/kermit/ckcsets.html
+ 325. http://www.columbia.edu/kermit/ckcsets.html
+ 326. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 327. http://www.columbia.edu/kermit/utf8.html
+ 328. http://www.columbia.edu/kermit/ckcsets.html
+ 329. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 330. ftp://ftp.isi.edu/in-notes/rfc2640.txt
+ 331. http://www.columbia.edu/kermit/ckermit80.html#top
+ 332. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 333. http://www.columbia.edu/kermit/ckermit.html
+ 334. http://www.columbia.edu/kermit/index.html
+ 335. http://www.columbia.edu/kermit/ckermit80.html#top
+ 336. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 337. http://www.columbia.edu/kermit/ckermit.html
+ 338. http://www.columbia.edu/kermit/index.html
+ 339. http://www.columbia.edu/kermit/ckermit80.html#top
+ 340. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 341. http://www.columbia.edu/kermit/ckermit.html
+ 342. http://www.columbia.edu/kermit/index.html
+ 343. http://www.columbia.edu/kermit/ftpscripts.html
+ 344. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 345. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 346. ftp://ftp.isi.edu/in-notes/rfc959.txt
+ 347. http://www.columbia.edu/kermit/ckscripts.html
+ 348. http://www.columbia.edu/kermit/ckermit80.html#top
+ 349. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 350. http://www.columbia.edu/kermit/ftpscript.html
+ 351. http://www.columbia.edu/kermit/ckermit.html
+ 352. http://www.columbia.edu/kermit/index.html
+ 353. http://www.columbia.edu/kermit/ckermit80.html#x3.11.1
+ 354. http://www.columbia.edu/kermit/ckermit80.html#x3.11.2
+ 355. http://www.columbia.edu/kermit/ckermit80.html#x3.11.3
+ 356. http://www.columbia.edu/kermit/ckermit80.html#x3.11.4
+ 357. http://www.columbia.edu/kermit/ckermit80.html#x3.11.5
+ 358. http://www.columbia.edu/kermit/ckermit.html
+ 359. http://www.columbia.edu/kermit/k95.html
+ 360. http://www.columbia.edu/kermit/ckermit80.html#x3.11.5
+ 361. ftp://ftp.isi.edu/in-notes/rfc959.txt
+ 362. ftp://ftp.isi.edu/in-notes/rfc2389.txt
+ 363. http://www.ietf.org/internet-drafts/draft-ietf-ftpext-mlst-16.txt
+ 364. http://www.columbia.edu/kermit/ftpclient.html
+ 365. http://www.columbia.edu/kermit/ckermit80.html#top
+ 366. http://www.columbia.edu/kermit/ckermit80.html#ftp
+ 367. http://www.columbia.edu/kermit/ckermit.html
+ 368. http://www.columbia.edu/kermit/index.html
+ 369. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 370. http://www.columbia.edu/kermit/ckermit80.html#ucs2
+ 371. http://www.columbia.edu/kermit/ckermit80.html#top
+ 372. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 373. http://www.columbia.edu/kermit/ckermit.html
+ 374. http://www.columbia.edu/kermit/index.html
+ 375. http://www.columbia.edu/kermit/ckermit80.html#top
+ 376. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 377. http://www.columbia.edu/kermit/ckermit.html
+ 378. http://www.columbia.edu/kermit/index.html
+ 379. http://www.columbia.edu/kermit/ckb2.htm
+ 380. http://www.columbia.edu/kermit/ckermit80.html#top
+ 381. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 382. http://www.columbia.edu/kermit/ckermit.html
+ 383. http://www.columbia.edu/kermit/index.html
+ 384. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 385. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 386. http://www.columbia.edu/kermit/ckermit80.html#x8.12
+ 387. http://www.columbia.edu/kermit/ckermit80.html#x8.1
+ 388. http://www.columbia.edu/kermit/ckermit80.html#x12
+ 389. http://www.columbia.edu/kermit/ckermit80.html#x8.12
+ 390. http://www.columbia.edu/kermit/ckermit80.html#top
+ 391. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 392. http://www.columbia.edu/kermit/ckermit.html
+ 393. http://www.columbia.edu/kermit/index.html
+ 394. http://www.columbia.edu/kermit/ckermit80.html#x8.14
+ 395. http://www.columbia.edu/kermit/ckermit80.html#top
+ 396. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 397. http://www.columbia.edu/kermit/ckermit.html
+ 398. http://www.columbia.edu/kermit/index.html
+ 399. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 400. http://www.columbia.edu/kermit/ckermit80.html#top
+ 401. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 402. http://www.columbia.edu/kermit/ckermit.html
+ 403. http://www.columbia.edu/kermit/index.html
+ 404. http://www.columbia.edu/kermit/ckermit80.html#x8.6
+ 405. http://www.columbia.edu/kermit/ckermit80.html#top
+ 406. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 407. http://www.columbia.edu/kermit/ckermit.html
+ 408. http://www.columbia.edu/kermit/index.html
+ 409. http://www.columbia.edu/kermit/ckermit80.html#top
+ 410. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 411. http://www.columbia.edu/kermit/ckermit.html
+ 412. http://www.columbia.edu/kermit/index.html
+ 413. http://www.columbia.edu/kermit/ckermit80.html#top
+ 414. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 415. http://www.columbia.edu/kermit/ckermit.html
+ 416. http://www.columbia.edu/kermit/index.html
+ 417. http://www.columbia.edu/kermit/ckermit80.html#fjoin
+ 418. http://www.columbia.edu/kermit/ckermit80.html#fsplit
+ 419. http://www.columbia.edu/kermit/ckermit80.html#x8.10
+ 420. http://www.columbia.edu/kermit/ckermit80.html#top
+ 421. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 422. http://www.columbia.edu/kermit/ckermit.html
+ 423. http://www.columbia.edu/kermit/index.html
+ 424. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 425. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 426. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 427. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 428. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 429. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 430. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 431. http://www.columbia.edu/kermit/ckermit80.html#x3.8
+ 432. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 433. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 434. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 435. http://www.columbia.edu/kermit/ckermit80.html#x3.2
+ 436. http://www.columbia.edu/kermit/ckermit80.html#x3
+ 437. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 438. http://www.columbia.edu/kermit/ckermit80.html#x8.13
+ 439. http://www.columbia.edu/kermit/ckermit80.html#x9
+ 440. http://www.columbia.edu/kermit/ckermit80.html#x8.10
+ 441. http://www.columbia.edu/kermit/ckermit80.html#x8.7.4
+ 442. http://www.columbia.edu/kermit/ckermit80.html#top
+ 443. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 444. http://www.columbia.edu/kermit/ckermit.html
+ 445. http://www.columbia.edu/kermit/index.html
+ 446. http://www.columbia.edu/kermit/ckermit80.html#top
+ 447. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 448. http://www.columbia.edu/kermit/ckermit.html
+ 449. http://www.columbia.edu/kermit/index.html
+ 450. http://www.columbia.edu/kermit/ckermit80.html#top
+ 451. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 452. http://www.columbia.edu/kermit/ckermit.html
+ 453. http://www.columbia.edu/kermit/index.html
+ 454. http://www.columbia.edu/kermit/ckermit80.html#x8.7
+ 455. http://www.columbia.edu/kermit/ckermit80.html#top
+ 456. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 457. http://www.columbia.edu/kermit/ckermit.html
+ 458. http://www.columbia.edu/kermit/index.html
+ 459. http://www.columbia.edu/kermit/ckermit80.html#scriptedit
+ 460. http://www.columbia.edu/kermit/ckermit80.html#top
+ 461. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 462. http://www.columbia.edu/kermit/ckermit.html
+ 463. http://www.columbia.edu/kermit/index.html
+ 464. http://www.columbia.edu/kermit/ckermit80.html#top
+ 465. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 466. http://www.columbia.edu/kermit/ckermit.html
+ 467. http://www.columbia.edu/kermit/index.html
+ 468. ftp://ftp.isi.edu/in-notes/rfc2822.txt
+ 469. ftp://ftp.isi.edu/in-notes/rfc2822.txt
+ 470. ftp://ftp.isi.edu/in-notes/rfc2822.txt
+ 471. ftp://ftp.isi.edu/in-notes/rfc2822.txt
+ 472. http://www.columbia.edu/kermit/ckermit80.html#top
+ 473. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 474. http://www.columbia.edu/kermit/ckermit.html
+ 475. http://www.columbia.edu/kermit/index.html
+ 476. http://www.columbia.edu/kermit/ckermit80.html#x8.1
+ 477. http://www.columbia.edu/kermit/ckermit80.html#top
+ 478. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 479. http://www.columbia.edu/kermit/ckermit.html
+ 480. http://www.columbia.edu/kermit/index.html
+ 481. http://www.columbia.edu/kermit/ckermit80.html#x8.2
+ 482. http://www.columbia.edu/kermit/ckermit80.html#top
+ 483. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 484. http://www.columbia.edu/kermit/ckermit.html
+ 485. http://www.columbia.edu/kermit/index.html
+ 486. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 487. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 488. http://www.columbia.edu/kermit/ckermit80.html#x8.2
+ 489. http://www.columbia.edu/kermit/ckermit80.html#top
+ 490. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 491. http://www.columbia.edu/kermit/ckermit.html
+ 492. http://www.columbia.edu/kermit/index.html
+ 493. http://www.columbia.edu/kermit/ckermit80.html#top
+ 494. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 495. http://www.columbia.edu/kermit/ckermit.html
+ 496. http://www.columbia.edu/kermit/index.html
+ 497. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 498. http://www.columbia.edu/kermit/ckermit80.html#top
+ 499. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 500. http://www.columbia.edu/kermit/ckermit.html
+ 501. http://www.columbia.edu/kermit/index.html
+ 502. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 503. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 504. http://www.columbia.edu/kermit/ckermit80.html#x9.6
+ 505. http://www.columbia.edu/kermit/ckermit80.html#top
+ 506. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 507. http://www.columbia.edu/kermit/ckermit.html
+ 508. http://www.columbia.edu/kermit/index.html
+ 509. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 510. http://www.columbia.edu/kermit/ckermit80.html#x9.8
+ 511. http://www.columbia.edu/kermit/ckermit80.html#top
+ 512. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 513. http://www.columbia.edu/kermit/ckermit.html
+ 514. http://www.columbia.edu/kermit/index.html
+ 515. http://www.columbia.edu/kermit/ckermit80.html#top
+ 516. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 517. http://www.columbia.edu/kermit/ckermit.html
+ 518. http://www.columbia.edu/kermit/index.html
+ 519. http://www.columbia.edu/kermit/ckermit80.html#top
+ 520. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 521. http://www.columbia.edu/kermit/ckermit.html
+ 522. http://www.columbia.edu/kermit/index.html
+ 523. mailto:thucdat@hotmail.com
+ 524. http://www.columbia.edu/kermit/ckermit80.html#x9.9.2
+ 525. http://www.columbia.edu/kermit/ckermit80.html#top
+ 526. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 527. http://www.columbia.edu/kermit/ckermit.html
+ 528. http://www.columbia.edu/kermit/index.html
+ 529. http://www.columbia.edu/kermit/ckermit80.html#top
+ 530. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 531. http://www.columbia.edu/kermit/ckermit.html
+ 532. http://www.columbia.edu/kermit/index.html
+ 533. http://www.columbia.edu/kermit/ckermit80.html#top
+ 534. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 535. http://www.columbia.edu/kermit/ckermit.html
+ 536. http://www.columbia.edu/kermit/index.html
+ 537. http://www.columbia.edu/kermit/ckermit80.html#x9.2
+ 538. http://www.columbia.edu/kermit/ckermit80.html#top
+ 539. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 540. http://www.columbia.edu/kermit/ckermit.html
+ 541. http://www.columbia.edu/kermit/index.html
+ 542. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 543. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 544. http://www.columbia.edu/kermit/ckermit80.html#top
+ 545. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 546. http://www.columbia.edu/kermit/ckermit.html
+ 547. http://www.columbia.edu/kermit/index.html
+ 548. http://www.columbia.edu/kermit/ckermit80.html#top
+ 549. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 550. http://www.columbia.edu/kermit/ckermit.html
+ 551. http://www.columbia.edu/kermit/index.html
+ 552. http://www.columbia.edu/kermit/ckermit80.html#top
+ 553. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 554. http://www.columbia.edu/kermit/ckermit.html
+ 555. http://www.columbia.edu/kermit/index.html
+ 556. http://www.columbia.edu/kermit/ckermit80.html#x4
+ 557. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 558. http://www.columbia.edu/kermit/ckermit80.html#x3.7
+ 559. http://www.columbia.edu/kermit/ckermit80.html#top
+ 560. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 561. http://www.columbia.edu/kermit/ckermit.html
+ 562. http://www.columbia.edu/kermit/index.html
+ 563. ftp://ftp.isi.edu/in-notes/rfc2217.txt
+ 564. http://www.columbia.edu/kermit/ckermit80.html#top
+ 565. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 566. ftp://kermit.columbia.edu/kermit/sredird/
+ 567. http://www.columbia.edu/kermit/ckermit.html
+ 568. http://www.columbia.edu/kermit/index.html
+ 569. http://www.columbia.edu/kermit/ckermi70.htm#x4.22
+ 570. http://www.columbia.edu/kermit/ckermit80.html#top
+ 571. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 572. http://www.columbia.edu/kermit/ckermit.html
+ 573. http://www.columbia.edu/kermit/index.html
+ 574. http://www.columbia.edu/kermit/ckermit80.html#x3.1.3
+ 575. http://www.columbia.edu/kermit/cuiksd.html
+ 576. http://www.columbia.edu/kermit/ckermit80.html#top
+ 577. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 578. http://www.columbia.edu/kermit/ckermit.html
+ 579. http://www.columbia.edu/kermit/index.html
+ 580. http://www.columbia.edu/kermit/ckermit80.html#top
+ 581. http://www.columbia.edu/kermit/ckermit80.html#contents
+ 582. http://www.columbia.edu/kermit/ckermit.html
+ 583. http://www.columbia.edu/kermit/index.html
+ 584. http://www.columbia.edu/kermit/index.html
diff --git a/ckermit-8.0.211/ckermod.ini b/ckermit-8.0.211/ckermod.ini
new file mode 100644
index 0000000..5848c3f
--- /dev/null
+++ b/ckermit-8.0.211/ckermod.ini
@@ -0,0 +1,144 @@
+; File CKERMOD.INI, Sample C-Kermit 7.0 customization file.
+;
+; This file, which is ONLY A SAMPLE, should be called:
+;
+;   .mykermrc   (UNIX, OS-9, Aegis, BeBox, Plan 9)
+;   CKERMOD.INI (VMS, OpenVMS, AOS/VS, OS/2, Amiga, Atari ST)
+;   ckermod.ini (Stratus VOS)
+;
+; This file is executed automatically by the standard C-Kermit initialization
+; file, CKERMIT.INI (or .kermrc).  This file is not executed by C-Kermit itself
+; unless the initialization file is not found.
+;
+; MODify this file to suit your needs and preferences, and install it in your
+; home directory.  Or replace it entirely with a new file.
+;
+; The design of this sample customization file lets you fill in a section for
+; each different operating system where you run C-Kermit.
+;
+; In UNIX, if you give this file execute permission and make sure the top
+; line indicates the full path of the C-Kermit 7.0-or-later executable, you
+; can execute this file directly, as if it was a shell script, except it is
+; interpreted by Kermit rather than the shell.  This lets you have as many
+; different startup files as you like, each suited to a particular purpose.
+;
+; Authors:  Christine Gianone, Frank da Cruz, Jeffrey Altman,
+;           The Kermit Project, Columbia University.
+; Creation: 23 November 1992 for C-Kermit 5A(188).
+; Modified: 30 June 1993 for edit 189.
+;           04 October 1994 for edit 190.
+;           17 April 1995 for edit 191.
+;            6 September 1996 for version 6.0, edit 192.
+;            1 January 2000 for version 7.0, edit 196.
+;           14 October 2001 for version 8.0, edit 200.
+
+ECHO
+ECHO Executing SAMPLE C-Kermit customization file \v(cmdfile) for \v(system)...
+ECHO { Please edit this file to reflect your needs and preferences.}
+ECHO
+;
+; ... and then remove the ECHO commands above.
+
+COMMENT - Settings that apply to all the systems I use:
+;
+set delay 1                  ; I escape back quickly
+set dial display on          ; I like to watch C-Kermit dial
+
+; Dialing locale and method
+;
+; SET DIAL COUNTRY-CODE 1    ; Uncomment and replace with yours
+; SET DIAL AREA-CODE 000     ; Uncomment and replace with yours
+; SET DIAL LD-PREFIX 1       ; Uncomment and replace with yours
+; SET DIAL INTL-PREFIX 011   ; Uncomment and replace with yours
+; SET DIAL METHOD TONE       ; Uncomment and replace with PULSE if necessary
+; SET DIAL DIRECTORY ... ... ; List dialing directory files here
+
+if < \v(version) 600192 -
+  stop 1 \v(cmdfile): C-Kermit 6.0.192 or later required.
+
+set take error on            ; Make errors fatal temporarily
+check if                     ; Do we have an IF command?
+set take error off           ; Yes we do, back to normal
+
+; The ON_EXIT macro is executed automatically when C-Kermit exits.
+; Define as desired.
+;
+define ON_EXIT echo Returning you to \v(system) now.
+
+; System-independent quick dialing macro.  Depends on having the
+; macros MYMODEM, MYPORT, and (optionally) MYSPEED defined in the
+; system-dependent sections below.
+;
+define MYDIAL {
+    if not defined MYMODEM end 1 {\%0: Modem type not defined.}
+    set modem type \m(MYMODEM)
+    if fail end 1 {\%0: \m(MYMODEM): Unsupported modem type.}
+    if not defined MYPORT end 1 {\%0: Communication port not defined.}
+    set port \m(MYPORT)
+    if fail end 1 {\%0: SET PORT \m(MYPORT) failed.}
+    if defined MYFLOW set flow \m(MYFLOW)
+    if fail end 1 {\%0: SET FLOW \m(MYFLOW) failed.}
+    if defined MYSPEED set speed \m(MYSPEED)
+    if fail end 1 {\%0: SET SPEED \m(MYSPEED) failed.}
+    dial \%1\%2\%3\%4\%5\%6\%7\%8\%9
+    end \v(status)
+}
+
+forward \v(system)              ; Go execute system-dependent commands
+
+:UNIX                           ; UNIX, all versions...
+define MYPORT /dev/cua          ; My dialing environment
+define MYMODEM usr              ; Replace these by what you actually have
+define MYSPEED 57600
+;
+; If you want all your downloads to go to the same directory, no matter
+; what your current directory is, uncomment and edit the following command:
+;
+;   set file download-directory ~/download ; Download directory for UNIX
+
+; Put other UNIX-specific commands here...
+end                             ; End of UNIX section
+
+:VMS                            ; VMS and OpenVMS
+define MYPORT TXA0:             ; My dialing environment
+define MYMODEM usr              ; Replace these by what you actually have
+define MYSPEED 57600
+; set file download-directory [\$(USER).DOWNLOAD] ; Download directory for VMS
+; Put other VMS-specific commands here...
+end                             ; End of VMS section
+
+:WIN32                          ; Windows and OS/2 customizations...
+:OS/2
+define MYPORT COM1              ; My dialing environment
+define MYMODEM usr              ; Replace these by what you actually have
+define MYSPEED 57600
+set command byte 8              ; Use 8 bits between Kermit and console
+set xfer char latin1            ; Use Latin-1 for text file transfer
+set term char latin1            ; And use Latin-1 during CONNECT mode
+; set file download-directory C:\DOWNLOADS
+end
+
+:OS9/68K                        ; OS-9/68000
+define MYPORT /t3               ; My dialing environment
+define MYMODEM usr              ; Replace these by what you actually have
+define MYSPEED 9600
+; set file download-directory ~/downloads
+end                             ; End of OS-9 section
+
+:AOS/VS                         ; Data General AOS/VS
+define MYPORT @con3             ; My dialing environment
+define MYMODEM usr              ; Replace these by what you actually have
+define MYSPEED 9600
+; set file download-directory \v(home)DOWNLOADS
+end
+
+; And so on, you get the idea...
+; Fill in the sections that apply to you.
+
+:Stratus_VOS			; Stratus VOS
+:Amiga                          ; Commodore Amiga
+:Atari_ST                       ; Atari ST
+:Macintosh                      ; Apple Macintosh
+:unknown                        ; Others
+
+; (End of CKERMOD.INI)
diff --git a/ckermit-8.0.211/ckuat2.h b/ckermit-8.0.211/ckuat2.h
new file mode 100644
index 0000000..5ee8e10
--- /dev/null
+++ b/ckermit-8.0.211/ckuat2.h
@@ -0,0 +1,363 @@
+/*
+  C K U A T 2 . H  --  Kerberos headers for C-Kermit
+
+  Copyright (C) 1985, 2004,
+    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
+*/
+/*
+ * 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 OS2
+#ifndef NOBLOCKDEF    /* already defined in kerberosiv/des.h */
+typedef struct des_ks_struct { Block _; } Schedule[16];
+#endif /* NOBLOCKDEF */
+#endif /* OS2 */
+#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
+
+#ifndef CRYPT_DLL
+extern int (*decrypt_input) P((int));
+extern void (*encrypt_output) P((unsigned char *, int));
+#endif /* CRYPT_DLL */
+
+int decrypt_ks_hack(unsigned char *, int);
+
+#endif /* __ENCRYPTION__ */
+#endif /* ENCRYPTION */
+
+#ifdef CRYPT_DLL
+struct _crypt_dll_init {
+    int version;
+
+    /* Version 1 variables */
+    int (*p_ttol)(char *,int);
+    int (*p_dodebug)(int,char *,char *,long);
+    int (*p_dohexdump)(char *,char *,int);
+    void (*p_tn_debug)(char *);
+    int (*p_vscrnprintf)(char *, ...);
+
+    /* Version 2 variables */
+    void * p_k5_context;
+
+    /* Version 3 variables */
+    void (*p_install_funcs)(char *,void *);
+
+    /* Version 5 variables */
+    unsigned long (*p_reqtelmutex)(unsigned long);
+    unsigned long (*p_reltelmutex)(void);
+};
+#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 */
diff --git a/ckermit-8.0.211/ckuath.c b/ckermit-8.0.211/ckuath.c
new file mode 100644
index 0000000..0ba4360
--- /dev/null
+++ b/ckermit-8.0.211/ckuath.c
@@ -0,0 +1,13287 @@
+char *ckathv = "Authentication, 8.0.232, 7 Feb 2004";
+/*
+  C K U A T H . C  --  Authentication for C-Kermit
+
+  Copyright (C) 1999, 2004,
+    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
+*/
+/*
+ * 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 */
+#ifdef OS2
+#ifdef NT
+#include <windows.h>
+#else /* NT */
+#define INCL_DOSMODULEMGR
+#include <os2.h>
+#endif /* NT */
+#endif /* OS2 */
+#endif /* CRYPT_DLL */
+
+#ifdef NT
+#define KRB5_AUTOCONF__
+#define NTLM
+#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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifndef malloc
+#ifndef VMS
+#ifndef FREEBSD4
+#ifndef OpenBSD
+#include <malloc.h>
+#endif /* OpenBSD */
+#endif /* FREEBSD4 */
+#endif /* VMS */
+#endif /* malloc */
+#ifdef OS2
+#include <io.h>
+#endif /* OS2 */
+
+#ifdef KRB5
+#ifdef HEIMDAL
+#ifdef printf
+#define saveprintf printf
+#undef printf
+#endif /* printf */
+#include "krb5.h"
+#include "com_err.h"
+#ifdef saveprintf
+#define printf saveprintf
+#endif /* saveprintf */
+#else /* HEIMDAL */
+#include "krb5.h"
+#include "profile.h"
+#include "com_err.h"
+#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
+#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 <pwd.h>
+#endif
+#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
+#define OPENSSL_ENABLE_OLD_DES_SUPPORT
+#include <openssl/des.h>
+#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 */
+
+/*
+ * 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"
+#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 <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+
+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 char szLocalHostName[UIDBUFLEN+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 <t_pwd.h>
+#include <t_client.h>
+#include <t_server.h>
+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 <srp.h>
+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;
+krb5_encrypt_block eblock;             /* eblock for encrypt/decrypt */
+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);
+#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
+    return(hSSPI != NULL);
+#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;
+              j<AUTHTYPLSTSZ && auth_type_user[j] != AUTHTYPE_NULL;
+              j++) {
+#ifdef NTLM
+            if (auth_type_user[j] == AUTHTYPE_NTLM)
+                i = ck_tn_auth_request_ntlm(i);
+#endif /* NTLM */
+#ifdef CK_SSL
+            if ( auth_type_user[j] == AUTHTYPE_SSL )
+                i = ck_tn_auth_request_ssl(i);
+#endif /* CK_SSL */
+#ifdef CK_SRP
+            if ( auth_type_user[j] == AUTHTYPE_SRP )
+                i = ck_tn_auth_request_srp(i);
+#endif /* SRP */
+#ifdef GSSAPI_K5
+            if ( auth_type_user[j] == AUTHTYPE_GSSAPI_KRB5 )
+                i = ck_tn_auth_request_gsskrb5(i);
+#endif /* GSSAPI_K5 */
+#ifdef KRB5
+            if ( auth_type_user[j] == AUTHTYPE_KERBEROS_V5 )
+                i = ck_tn_auth_request_krb5(i);
+#endif /* KRB5 */
+#ifdef KRB4
+            if ( auth_type_user[j] == AUTHTYPE_KERBEROS_V4 )
+                i = ck_tn_auth_request_krb4(i);
+#endif /* KRB4 */
+        }
+    }
+
+    str_request[i++] = IAC;
+    str_request[i++] = SE;
+    if ( deblog || tn_deb || debses ) {
+        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_request, i);
+#ifdef OS2
+    ReleaseTelnetMutex();
+#endif
+    if ( rc == i )
+        return(0);
+    else
+        return(-1);
+}
+
+#ifdef CK_ENCRYPTION
+VOID
+ck_tn_enc_start()
+{
+    if (!TELOPT_ME(TELOPT_ENCRYPTION) && !TELOPT_U(TELOPT_ENCRYPTION))
+        return;
+    if (!TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop &&
+         (!encrypt_is_decrypting() || !encrypt_is_encrypting())) {
+        debug(F110,"ck_tn_enc_start","nothing to do",0);
+        return;
+    }
+    TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
+    if (TELOPT_ME(TELOPT_ENCRYPTION) && !encrypt_is_encrypting()) {
+        debug(F110,"ck_tn_enc_start","encrypt_request_start",0);
+        encrypt_request_start();
+    }
+    if (TELOPT_U(TELOPT_ENCRYPTION) && !encrypt_is_decrypting()) {
+        debug(F110,"ck_tn_enc_start","encrypt_send_request_start",0);
+        encrypt_send_request_start();
+    }
+    tn_wait("encrypt start");
+    tn_push();
+}
+
+VOID
+ck_tn_enc_stop()
+{
+    if (!TELOPT_ME(TELOPT_ENCRYPTION) && !TELOPT_U(TELOPT_ENCRYPTION))
+        return;
+    if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop ||
+         !(encrypt_is_decrypting() || encrypt_is_encrypting())) {
+        debug(F110,"ck_tn_enc_stop","nothing to do",0);
+      return;
+    }
+    TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 1;
+    if (TELOPT_U(TELOPT_ENCRYPTION) && encrypt_is_decrypting()) {
+        debug(F110,"ck_tn_enc_stop","encrypt_send_request_end",0);
+        encrypt_send_request_end();
+    }
+    if (TELOPT_ME(TELOPT_ENCRYPTION) && encrypt_is_encrypting()) {
+        debug(F110,"ck_tn_enc_stop","encrypt_send_end",0);
+        encrypt_send_end();
+    }
+    tn_wait("encrypt stop");
+    tn_push();
+}
+#endif /* CK_ENCRYPTION */
+
+/*  C K _ K R B _ T N _ S B _ A U T H
+ *  An interface between the C-Kermit Telnet Command Parser and the Authent-
+ *  ication option parser implemented in the Kerberos Telnet client.
+ *
+ *  sb   - the subnegotiation as calculated in ckcnet.c
+ *  len  - the length of the buffer
+ *
+ *  Returns: 0 on success and -1 on failure
+ */
+
+int
+#ifdef CK_ANSIC
+ck_tn_sb_auth(char * sb, int len)
+#else /* CK_ANSIC */
+ck_tn_sb_auth(sb,len) char * sb; int len;
+#endif /* CK_ANSIC */
+{
+    /* auth_parse() assumes that sb starts at pos 1 not 0 as in ckcnet.c */
+    /* and it wants the length to exclude the IAC SE bytes               */
+    CHAR * buf;
+    int rc = -1;
+
+    buf = malloc(len-1);
+    if ( !buf ) return(-1);
+
+    buf[0] = SB;
+    memcpy( &buf[1], sb, len-2 );
+    rc = auth_parse(buf,len-1);
+    free(buf);
+    debug(F111,"ck_tn_sb_auth","rc",rc);
+    if (rc == AUTH_FAILURE) {
+        authentication_version = AUTHTYPE_NULL;
+#ifndef NOLOCAL
+#ifdef OS2
+        ipadl25();
+#endif /* OS2 */
+#endif /* NOLOCAL */
+        return(-1);
+    }
+#ifndef NOLOCAL
+#ifdef OS2
+    ipadl25();
+#endif /* OS2 */
+#endif /* NOLOCAL */
+    return(0);
+}
+
+/*  C K _ K R B _ T N _ S B _ E N C R Y P T
+ *  An interface between the C-Kermit Telnet Command Parser and the Encryption
+ *  option parser implemented in the Kerberos Telnet client.
+ *
+ *  sb   - the subnegotiation as calculated in ckcnet.c
+ *  len  - the length of the buffer
+ *
+ *  Returns: Always returns 0 for success since encrypt_parse is void
+ */
+
+
+int
+#ifdef CK_ANSIC
+ck_tn_sb_encrypt(char * sb, int len)
+#else
+ck_tn_sb_encrypt(sb,len) char * sb; int len;
+#endif /* CK_ANSIC */
+{
+    /* encrypt_parse() assumes that sb starts at pos 1 not 0 as in ckcnet.c */
+    /* and it wants the length to exclude the IAC SE bytes                  */
+#ifdef CK_ENCRYPTION
+    char * buf;
+    int rc = -1;
+
+    buf = malloc(len-1);
+    if ( !buf ) return(-1);
+
+    buf[0] = SB;
+    memcpy( &buf[1], sb, len-2 );
+    rc = encrypt_parse(buf,len-1);
+
+    if (rc < 0) {
+        free(buf);
+        return(-1);
+    }
+
+    /* This is a hack.  It does not belong here but should really be in */
+    /* encrypt_parse() but in K95 the encrypt_parse() routine does not  */
+    /* have access to the telopt_states array.                          */
+    if ( buf[1] == ENCRYPT_REQEND )
+        TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 1;
+    else if ( buf[1] == ENCRYPT_REQSTART )
+        TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0;
+#ifndef NOLOCAL
+#ifdef OS2
+    ipadl25();
+#endif /* OS2 */
+#endif /* NOLOCAL */
+    free(buf);
+#endif /* ENCRYPTION */
+    return(0);
+}
+
+
+/*  C K _ K R B _ E N C R Y P T I N G
+ *  Returns 1 if we are encrypting and 0 if we are not
+ */
+
+int
+#ifdef CK_ANSIC
+ck_tn_encrypting(VOID)
+#else /* CK_ANSIC */
+ck_tn_encrypting()
+#endif /* CK_ANSIC */
+{
+#ifdef CK_ENCRYPTION
+    if ( g_kstream == NULL )
+        return(0);
+    if ( g_kstream->encrypt && 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
+      hexdump("from plaintext", s, n);
+#endif
+        i.ptr = s;
+        i.length = n;
+        g_kstream->encrypt(&i, NULL);
+#ifdef DEBUG
+        hexdump("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
+        hexdump("from cyphertext", s, n);
+#endif
+
+        i.ptr = s;
+        i.length = n;
+        g_kstream->decrypt(&i, NULL);
+#ifdef DEBUG
+        hexdump("to plaintext", s, n);
+#endif
+    }
+    else debug(F101,"ck_tn_decrypt not decrypting","",n);
+#endif /* ENCRYPTION */
+}
+
+/*  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 i;
+        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);
+}
+
+/*  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 i;
+        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);
+}
+
+/*  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 i;
+        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);
+}
+
+#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<AUTHTYPLSTSZ && auth_type_user[i] != AUTHTYPE_NULL;
+          i++ ) {
+        if ( auth_type_user[i] == at )
+            return(1);
+    }
+
+    return(0);
+}
+
+
+/*
+ * Function: Parse authentication send 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 unsigned char send_list[512];
+static int  send_len = 0;
+
+_PROTOTYP(static int auth_send, (unsigned char *parsedat, int end_sub));
+
+static int
+#ifdef CK_ANSIC
+auth_resend(int type)
+#else
+auth_resend(type) int type;
+#endif /* CK_ANSIC */
+{
+    int i=2;
+    while (i+1 <= send_len) {
+        if (send_list[i] == type) {
+            int j;
+            send_len -= 2;
+            for (j = i; j < send_len; j++)
+                send_list[j] = send_list[j+2];
+        } else {
+            i += 2;
+        }
+    }
+    return(auth_send(send_list,send_len));
+}
+
+static int
+#ifdef CK_ANSIC
+auth_send(unsigned char *parsedat, int end_sub)
+#else
+auth_send(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+    static unsigned char buf[4096];
+    unsigned char *pname;
+    int plen;
+    int r;
+    int i;
+    int mode;
+#ifdef MIT_CURRENT
+#ifdef CK_ENCRYPTION
+    krb5_data data;
+    krb5_enc_data encdata;
+    krb5_error_code code;
+    krb5_keyblock random_key;
+#endif /* ENCRYPTION */
+#endif /* MIT_CURRENT */
+#ifdef KRB5
+    int krb5_msg = 0;
+#endif /* KRB5 */
+#ifdef KRB4
+    int krb4_msg = 0;
+#endif /* KRB4 */
+#ifdef GSSAPI_KRB5
+    int gssk5_msg = 0;
+#endif /* GSSAPI_KRB5 */
+    int iaccnt=0;
+
+#ifdef CK_SSL
+    if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows)
+        return(AUTH_SUCCESS);
+#endif /* CK_SSL */
+
+    auth_how = -1;              /* We have not found an auth method  */
+    auth_crypt = 0;             /* We are not using encryption (yet) */
+    send_len = end_sub > 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<NTLMSecBuf[0].cbBuffer ; i++ ) {
+            if ( ((char *)NTLMSecBuf[0].pvBuffer)[i] == IAC )
+                iaccnt++;
+        }
+
+        if ( ( 2*sizeof(ULONG) + NTLMSecBuf[0].cbBuffer + iaccnt + 10)  <
+             sizeof(buf) ) {
+            length = copy_for_net(&buf[7],(char *)&NTLMSecBuf[0],
+                                   2*sizeof(ULONG));
+            length += copy_for_net(&buf[7+length], NTLMSecBuf[0].pvBuffer,
+                                  NTLMSecBuf[0].cbBuffer);
+        }
+        sprintf(&buf[7+length], "%c%c", IAC, SE);
+
+        if (deblog || tn_deb || debses) {
+            int i;
+            ckmakxmsg(tn_msg,TN_MSG_LEN,
+                      "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION),
+                      " IS ",AUTHTYPE_NAME(authentication_version)," ",
+                      AUTHMODE_NAME(mode)," NTLM_AUTH ",
+                       NULL,NULL,NULL,NULL,NULL
+                      );
+            tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],length);
+            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((CHAR *)buf, length+9);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+        break;
+    }
+#endif /* NTLM */
+#ifdef KRB4
+    case AUTHTYPE_KERBEROS_V4:
+        for ( i=0 ; i<k4_auth.length ; i++ ) {
+            if ( k4_auth.dat[i] == IAC )
+                iaccnt++;
+        }
+
+        if ( k4_auth.length + iaccnt + 10 < sizeof(buf) )
+          k4_auth.length = copy_for_net(&buf[7], k4_auth.dat, k4_auth.length);
+        else
+            k4_auth.length = 0;
+        sprintf(&buf[k4_auth.length+7], "%c%c", IAC, SE);
+
+        if (deblog || tn_deb || debses) {
+            int i;
+            ckmakxmsg(tn_msg,TN_MSG_LEN,
+                      "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION)," IS ",
+                      AUTHTYPE_NAME(authentication_version)," ",
+                      AUTHMODE_NAME(mode)," AUTH ",
+                      NULL,NULL,NULL,NULL,NULL
+                     );
+            tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],k4_auth.length);
+            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((CHAR *)buf, k4_auth.length+9);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+
+#ifndef REMOVE_FOR_EXPORT
+#ifdef CK_ENCRYPTION
+        /*
+         * If we are doing mutual authentication, get set up to send
+         * the challenge, and verify it when the response comes back.
+         */
+        if ((auth_how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+            register int i;
+            int rc = 0;
+
+#ifdef MIT_CURRENT
+            data.data = cred.session;
+            data.length = 8; /* sizeof(cred.session) */;
+
+            if (code = krb5_c_random_seed(k5_context, &data)) {
+                com_err("libtelnet", code,
+                         "while seeding random number generator");
+                return(0);
+            }
+
+            if (code = krb5_c_make_random_key(k5_context,
+                                               ENCTYPE_DES_CBC_RAW,
+                                               &random_key)) {
+                com_err("libtelnet", code,
+                         "while creating random session key");
+                return(0);
+            }
+
+            /* the krb4 code uses ecb mode, but on a single block
+            with a zero ivec, ecb and cbc are the same */
+            k4_krbkey.enctype = ENCTYPE_DES_CBC_RAW;
+            k4_krbkey.length = 8;
+            k4_krbkey.contents = cred.session;
+
+            encdata.ciphertext.data = random_key.contents;
+            encdata.ciphertext.length = random_key.length;
+            encdata.enctype = ENCTYPE_UNKNOWN;
+
+            data.data = k4_session_key;
+            data.length = 8;
+
+            code = krb5_c_decrypt(k5_context, &k4_krbkey, 0, 0,
+                                   &encdata, &data);
+
+            krb5_free_keyblock_contents(k5_context, &random_key);
+
+            if (code) {
+                com_err("libtelnet", code, "while encrypting random key");
+                return(0);
+            }
+
+            encdata.ciphertext.data = k4_session_key;
+            encdata.ciphertext.length = 8;
+            encdata.enctype = ENCTYPE_UNKNOWN;
+
+            data.data = k4_challenge;
+            data.length = 8;
+
+            code = krb5_c_decrypt(k5_context, &k4_krbkey, 0, 0,
+                                   &encdata, &data);
+#else /* MIT_CURRENT */
+            memset(k4_sched,0,sizeof(Schedule));
+            hexdump("auth_send",cred.session,8);
+            rc = des_key_sched(cred.session, k4_sched);
+            if ( rc == -1 ) {
+                printf("?Invalid DES key specified in credentials\r\n");
+                debug(F110,"auth_send",
+                      "invalid DES Key specified in credentials",0);
+            } else if ( rc == -2 ) {
+                printf("?Weak DES key specified in credentials\r\n");
+                debug(F110,"auth_send",
+                      "weak DES Key specified in credentials",0);
+            } else if ( rc != 0 ) {
+                printf("?DES Key Schedule not set by credentials\r\n");
+                debug(F110,"auth_send",
+                      "DES Key Schedule not set by credentials",0);
+            }
+            hexdump("auth_send schedule",k4_sched,8*16);
+
+            des_set_random_generator_seed(cred.session);
+
+            do {
+                des_new_random_key(k4_session_key);
+                des_fixup_key_parity(k4_session_key);
+            } while ( ck_des_is_weak_key(k4_session_key) );
+
+            hexdump("auth_send des_new_random_key(k4_session_key)",
+                     k4_session_key,8);
+
+            /* Decrypt the session key so that we can send it to the */
+            /* host as a challenge                                   */
+#ifdef NT
+            des_ecb_encrypt(k4_session_key, k4_session_key, k4_sched, 0);
+#else /* NT */
+            des_ecb_encrypt(&k4_session_key, &k4_session_key, k4_sched, 0);
+#endif /* NT */
+            hexdump(
+                "auth_send des_ecb_encrypt(k4_session_key,k4_session_key,0)",
+                k4_session_key,8
+                    );
+            /* Prepare the result of the challenge */
+            /* Decrypt the session_key, add 1, and then encrypt it */
+            /* The result stored in k4_challenge should match the  */
+            /* KRB4_RESPONSE value from the host.                  */
+#ifdef NT
+            des_ecb_encrypt(k4_session_key, k4_challenge, k4_sched, 0);
+#else /* NT */
+            des_ecb_encrypt(&k4_session_key, &k4_challenge, k4_sched, 0);
+#endif /* NT */
+
+            hexdump("auth_send des_ecb_encrypt(k4_session_key,k4_challenge,0)",
+                     k4_challenge,8);
+#endif /* MIT_CURRENT */
+            /*
+            * Increment the challenge by 1, and encrypt it for
+            * later comparison.
+            */
+            for (i = 7; 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;
+            }
+            hexdump("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 */
+            hexdump("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<gss_send_tok.length ; i++ ) {
+            if ( ((char *)gss_send_tok.value)[i] == IAC )
+                iaccnt++;
+        }
+
+        if ( gss_send_tok.length + iaccnt + 10 < sizeof(buf) )
+            gss_send_tok.length = copy_for_net(&buf[7], gss_send_tok.value,
+                                               gss_send_tok.length);
+        else
+            gss_send_tok.length = 0;
+        sprintf(&buf[gss_send_tok.length+7], "%c%c", IAC, SE);       /* safe */
+        if (deblog || tn_deb || debses) {
+            int i;
+            ckmakxmsg(tn_msg,TN_MSG_LEN,
+                      "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION)," IS ",
+                      AUTHTYPE_NAME(authentication_version)," ",
+                      AUTHMODE_NAME(mode)," AUTH ",
+                      NULL,NULL,NULL,NULL,NULL
+                     );
+            tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],gss_send_tok.length);
+            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((CHAR *)buf, gss_send_tok.length+9);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+        break;
+#endif /* GSSAPI_KRB5 */
+#ifdef KRB5
+    case AUTHTYPE_KERBEROS_V5:
+        debug(F111,"auth_send KRB5","k5_auth.length",k5_auth.length);
+        for ( i=0 ; i<k5_auth.length ; i++ ) {
+            if ( ((char *)k5_auth.data)[i] == IAC )
+                iaccnt++;
+        }
+
+        if ( k5_auth.length + iaccnt + 10 < sizeof(buf) )
+          k5_auth.length = copy_for_net(&buf[7], k5_auth.data, k5_auth.length);
+        else {
+          debug(F100,"auth_send() KRB5 auth data too large for buffer","",0);
+          k5_auth.length = 0;
+        }
+
+        sprintf(&buf[k5_auth.length+7], "%c%c", IAC, SE);       /* safe */
+        if (deblog || tn_deb || debses) {
+            int i;
+            ckmakxmsg(tn_msg,TN_MSG_LEN,
+                      "TELNET SENT SB ",TELOPT(TELOPT_AUTHENTICATION)," IS ",
+                      AUTHTYPE_NAME(authentication_version)," ",
+                      AUTHMODE_NAME(mode)," AUTH ",
+                      NULL,NULL,NULL,NULL,NULL
+                     );
+            tn_hex((char *)tn_msg,TN_MSG_LEN,&buf[7],k5_auth.length);
+            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((CHAR *)buf, k5_auth.length+9);
+#ifdef OS2
+        ReleaseTelnetMutex();
+#endif
+#ifdef HEIMDAL
+        krb5_data_free(&k5_auth);
+#else /* HEIMDAL */
+        krb5_free_data_contents(k5_context,&k5_auth);
+        memset(&k5_auth,0,sizeof(krb5_data));
+#endif /* HEIMDAL */
+        break;
+#endif /* KRB5 */
+    }
+    return AUTH_SUCCESS;
+}
+
+/*
+ * Function: 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
+auth_reply(unsigned char *parsedat, int end_sub)
+#else
+auth_reply(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+    int n = AUTH_FAILURE;
+
+    if ( parsedat[2] != authentication_version ) {
+        printf("Authentication version mismatch (%s [%d] != %s [%d])\r\n",
+                AUTHTYPE_NAME(parsedat[2]),parsedat[2],
+                AUTHTYPE_NAME(authentication_version),authentication_version);
+        auth_finished(AUTH_REJECT);
+        return(AUTH_FAILURE);
+    }
+    if ( parsedat[3] != (auth_how|auth_crypt|auth_fwd) ) {
+        printf("Authentication mode mismatch (%s != %s)\r\n",
+                AUTHMODE_NAME(parsedat[3]),
+                AUTHMODE_NAME(auth_how|auth_crypt|auth_fwd));
+        auth_finished(AUTH_REJECT);
+        return(AUTH_FAILURE);
+    }
+
+#ifdef KRB4
+    if (authentication_version == AUTHTYPE_KERBEROS_V4)
+        n = k4_auth_reply(parsedat, end_sub);
+#endif
+#ifdef KRB5
+    if (authentication_version == AUTHTYPE_KERBEROS_V5)
+        n = k5_auth_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#endif
+#ifdef CK_SRP
+    if (authentication_version == AUTHTYPE_SRP) {
+#ifndef PRE_SRP_1_7_3
+        n = new_srp_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#else /* PRE_SRP_1_7_3 */
+        n = srp_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#endif /* PRE_SRP_1_7_3 */
+    }
+#endif /* SRP */
+#ifdef CK_SSL
+    if (authentication_version == AUTHTYPE_SSL)
+        n = ssl_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#endif /* SSL */
+#ifdef NTLM
+    if (authentication_version == AUTHTYPE_NTLM)
+        n = ntlm_reply(auth_how|auth_crypt|auth_fwd, parsedat, end_sub);
+#endif /* NTLM */
+    return n;
+}
+
+
+/*
+ * Function: 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
+auth_is(unsigned char *parsedat, int end_sub)
+#else
+auth_is(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+    int n = AUTH_FAILURE;
+
+    if ( parsedat[2] == AUTHTYPE_NULL ) {
+        auth_finished(AUTH_REJECT);
+        return(AUTH_FAILURE);
+    }
+
+    /*
+     *  If CLIENT_CHOOSE_ONCE is selected the server will not allow the
+     *  client to switch to an alternate authentication method if the one
+     *  it originally selected fails.  (ie, if the host's SRP parameters
+     *  are invalid.)  However, I think this is a bit of a security risk
+     *  since allowing that functionality means that it is impossible to
+     *  detect if an attack is being carried out on
+     */
+#define CLIENT_CHOOSE_ONCE
+#ifdef CLIENT_CHOOSE_ONCE
+    if ( authentication_version == AUTHTYPE_AUTO )
+#endif /* CLIENT_CHOOSE_ONCE */
+    {
+        /* this block of code needs to check the initial parameters */
+        /* to ensure that those returned match one of the sets that */
+        /* were sent to the client in the first place.              */
+
+        int i=0;
+        for ( i=4; str_request[i] != IAC ; i+=2) {
+            if (str_request[i] == parsedat[2] &&
+                 str_request[i+1] == parsedat[3])
+                break;
+        }
+
+        if ( str_request[i] == IAC ) {
+            printf("Invalid authentication type pair (%s,%s)\r\n",
+                    AUTHTYPE_NAME(parsedat[2]),
+                    AUTHMODE_NAME(parsedat[3]));
+            auth_finished(AUTH_REJECT);
+            return(AUTH_FAILURE);
+        }
+
+        if (authentication_version != parsedat[2]) {
+            authentication_version = parsedat[2];
+            auth_how = (parsedat[3] & AUTH_HOW_MASK);
+            auth_crypt = (parsedat[3] & AUTH_ENCRYPT_MASK);
+            auth_fwd = (parsedat[3] & INI_CRED_FWD_MASK);
+            debug(F111,"auth_is","authentication_version",
+                  authentication_version);
+            debug(F111,"auth_is","auth_how",auth_how);
+            debug(F111,"auth_is","auth_crypt",auth_crypt);
+            debug(F111,"auth_is","auth_fwd",auth_fwd);
+        }
+    }
+
+#ifdef CLIENT_CHOOSE_ONCE
+    if ( parsedat[2] != authentication_version ) {
+        printf("Authentication version mismatch (%s [%d] != %s [%d])\r\n",
+                AUTHTYPE_NAME(parsedat[2]),parsedat[2],
+                AUTHTYPE_NAME(authentication_version),authentication_version);
+        auth_finished(AUTH_REJECT);
+        return(AUTH_FAILURE);
+    }
+    if ( parsedat[3] != (auth_how|auth_crypt|auth_fwd) ) {
+        printf("Authentication mode mismatch (%s != %s)\r\n",
+                AUTHMODE_NAME(parsedat[3]),
+                AUTHMODE_NAME(auth_how|auth_crypt|auth_fwd));
+        auth_finished(AUTH_REJECT);
+        return(AUTH_FAILURE);
+    }
+#endif /* CLIENT_CHOOSE_ONCE */
+
+    switch (authentication_version) {
+#ifdef KRB4
+    case AUTHTYPE_KERBEROS_V4:
+        n = k4_auth_is(parsedat, end_sub);
+        break;
+#endif
+#ifdef KRB5
+    case AUTHTYPE_KERBEROS_V5:
+        n = k5_auth_is(parsedat[3],parsedat, end_sub);
+        break;
+#endif
+#ifdef CK_SRP
+    case AUTHTYPE_SRP:
+#ifndef PRE_SRP_1_7_3
+        n = new_srp_is(parsedat[3], parsedat, end_sub);
+#else /* PRE_SRP_1_7_3 */
+        n = srp_is(parsedat[3], parsedat, end_sub);
+#endif /* PRE_SRP_1_7_3 */
+        break;
+#endif /* SRP */
+#ifdef CK_SSL
+    case AUTHTYPE_SSL:
+        TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+        TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+        n = ssl_is(parsedat, end_sub);
+        break;
+#endif /* SSL */
+#ifdef NTLM
+    case AUTHTYPE_NTLM:
+        TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+        TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+        n = ntlm_is(parsedat, end_sub);
+        break;
+#endif /* NTLM */
+    case AUTHTYPE_NULL:
+    default:
+        n = AUTH_FAILURE;
+    }
+    debug(F111,"auth_is","n",n);
+    return n;
+}
+
+/*
+ * Function: Parse authentication NAME 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
+auth_name(unsigned char *parsedat, int end_sub)
+#else
+auth_name(parsedat,end_sub) unsigned char *parsedat; int end_sub;
+#endif
+{
+    int len = (end_sub-2) > 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 */
+        hexdump(
+            "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;
+        }
+
+        hexdump("KRB4_RESPONSE &parsedat[5]",&parsedat[5],8);
+#ifdef CK_ENCRYPTION
+        hexdump("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;
+        hexdump("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<INST_SZ;i++ ) {
+                if ( instance[i] == '.' )
+                    instance[i] = '\0';
+                else
+                    instance[i] = tolower(instance[i]);
+            }
+        } else {
+            instance[0] = '*';
+            instance[1] = 0;
+        }
+
+        if (r = krb_rd_req(&k4_auth,
+                            krb4_d_srv ? krb4_d_srv : KRB4_SERVICE_NAME,
+                            instance, 0, &k4_adat, k4_keytab)) {
+
+            hexdump("k4_adat", &k4_adat, sizeof(AUTH_DAT));
+            krb_kntoln(&k4_adat, k4_name);
+            ckmakmsg(strTmp,sizeof(strTmp),
+                     "Kerberos failed him as ", k4_name,NULL,NULL);
+            printf("%s\r\n",strTmp);
+            krb4_errno = r;
+            makestr(&krb4_errmsg,strTmp);
+            SendK4AuthSB(KRB_REJECT, (void *)krb_get_err_text_entry(r), -1);
+            auth_finished(AUTH_REJECT);
+            return AUTH_FAILURE;
+        }
+
+#ifdef CK_ENCRYPTION
+        memcpy((void *)k4_session_key, (void *)k4_adat.session,
+                sizeof(Block));                 /* safe */
+        hexdump("k4_auth_is k4_session_key",k4_session_key,sizeof(Block));
+#endif /* ENCRYPTION */
+        krb_kntoln(&k4_adat, k4_name);
+
+        ckstrncpy(szUserNameAuthenticated,k4_name,UIDBUFLEN);
+        if (szUserNameRequested && !kuserok(&k4_adat, k4_name)) {
+            SendK4AuthSB(KRB_ACCEPT, (void *)0, 0);
+            if ( !strcmp(k4_name,szUserNameRequested) )
+                auth_finished(AUTH_VALID);
+            else
+                auth_finished(AUTH_USER);
+            accept_complete = 1;
+        }
+        else {
+            SendK4AuthSB(KRB_REJECT,
+                  (void *)"user is not authorized", -1);
+            auth_finished(AUTH_REJECT);
+            krb4_errno = r;
+            makestr(&krb4_errmsg,"user is not authorized");
+            return(AUTH_FAILURE);
+        }
+        break;
+
+    case KRB4_CHALLENGE:
+        debug(F110,"k4_auth_is","KRB_CHALLENGE",0);
+#ifndef CK_ENCRYPTION
+        SendK4AuthSB(KRB4_RESPONSE, (void *)0, 0);
+#else   /* ENCRYPTION */
+        if (!VALIDKEY(k4_session_key)) {
+            /*
+            * We don't have a valid session key, so just
+            * send back a response with an empty session
+            * key.
+            */
+            SendK4AuthSB(KRB4_RESPONSE, (void *)0, 0);
+            mutual_complete = 1;
+            break;
+        }
+
+        /*
+        * Initialize the random number generator since it's
+        * used later on by the encryption routine.
+        */
+#ifdef MIT_CURRENT
+        kdata.data = k4_session_key;
+        kdata.length = 8;
+
+        if (code = krb5_c_random_seed(k5_context, &kdata)) {
+            com_err("k4_auth_is", code,
+                     "while seeding random number generator");
+            auth_finished(AUTH_REJECT);
+            return AUTH_FAILURE;
+        }
+
+        memcpy((void *)datablock, (void *)data, sizeof(Block)); /* safe */
+        /*
+        * Take the received encrypted challenge, and encrypt
+        * it again to get a unique session_key for the
+        * ENCRYPT option.
+        */
+        k4_krbkey.enctype = ENCTYPE_DES_CBC_RAW;
+        k4_krbkey.length = 8;
+        k4_krbkey.contents = k4_session_key;
+
+        kdata.data = datablock;
+        kdata.length = 8;
+
+        encdata.ciphertext.data = tmpkey;
+        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 encrypting random key");
+            auth_finished(AUTH_REJECT);
+            return AUTH_FAILURE;
+        }
+
+#ifdef CK_SSL
+        if (!(ssl_active_flag || tls_active_flag))
+#endif /* CK_SSL */
+        {
+            skey.type = SK_DES;
+            skey.length = 8;
+            skey.data = tmpkey;
+            encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
+        }
+        /*
+        * Now decrypt the received encrypted challenge,
+        * increment by one, re-encrypt it and send it back.
+        */
+        encdata.ciphertext.data = datablock;
+        encdata.ciphertext.length = 8;
+        encdata.enctype = ENCTYPE_UNKNOWN;
+
+        kdata.data = k4_challenge;
+        kdata.length = 8;
+
+        if (code = krb5_c_decrypt(k5_context, &k4_krbkey, 0, 0,
+                                   &encdata, &kdata)) {
+            com_err("k4_auth_is", code, "while decrypting challenge");
+            auth_finished(AUTH_REJECT);
+            return AUTH_FAILURE;
+        }
+#else /* MIT_CURRENT */
+        des_set_random_generator_seed(k4_session_key);
+        r = des_key_sched(k4_session_key, k4_sched);
+        if ( r == -1 ) {
+            printf("?Invalid DES key specified in credentials\r\n");
+            debug(F110,"auth_is CHALLENGE",
+                   "invalid DES Key specified in credentials",0);
+        } else if ( r == -2 ) {
+            printf("?Weak DES key specified in credentials\r\n");
+            debug(F110,"auth_is CHALLENGE",
+                   "weak DES Key specified in credentials",0);
+        } else if ( r != 0 ) {
+            printf("?DES Key Schedule not set by credentials\r\n");
+            debug(F110,"auth_is CHALLENGE",
+                   "DES Key Schedule not set by credentials",0);
+        }
+        hexdump("auth_is schedule",k4_sched,8*16);
+
+        memcpy((void *)datablock, (void *)data, sizeof(Block)); /* safe */
+        hexdump("auth_is challege",datablock,sizeof(Block));
+
+        /*
+        * Take the received encrypted challenge, and encrypt
+        * it again to get a unique k4_session_key for the
+        * ENCRYPT option.
+        */
+#ifdef NT
+        des_ecb_encrypt(datablock, k4_session_key, k4_sched, 1);
+#else /* NT */
+        des_ecb_encrypt(&datablock, &k4_session_key, k4_sched, 1);
+#endif /* NT */
+        hexdump("auth_is des_ecb_encrypt(datablock,k4_session_key,1)",
+                 k4_session_key,8);
+
+#ifdef CK_SSL
+        if (!(ssl_active_flag || tls_active_flag))
+#endif /* CK_SSL */
+        {
+            skey.type = SK_DES;
+            skey.length = 8;
+            skey.data = k4_session_key;
+            encrypt_session_key(&skey, AUTH_SERVER_TO_CLIENT);
+        }
+        /*
+        * Now decrypt the received encrypted challenge,
+        * increment by one, re-encrypt it and send it back.
+        */
+#ifdef NT
+        des_ecb_encrypt(datablock, k4_challenge, k4_sched, 0);
+#else /* NT */
+        des_ecb_encrypt(&datablock, &k4_challenge, k4_sched, 0);
+#endif /* NT */
+        hexdump("auth_is des_ecb_encrypt(datablock,k4_challenge,0)",
+                 k4_session_key,8);
+#endif /* MIT_CURRENT */
+        for (r = 7; r >= 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;
+        }
+        hexdump("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 */
+        hexdump("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,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
+    r = krb5_auth_setkeytype(k5_context, auth_context, KEYTYPE_DES);
+    if (r)
+        com_err(NULL, r, "while setting auth keytype");
+    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 {
+#ifdef HEIMDAL
+                    switch ( k5_session_key->keytype ) {
+                    case ETYPE_DES_CBC_CRC:
+                    case ETYPE_DES_CBC_MD5:
+                    case ETYPE_DES_CBC_MD4:
+                        skey.type = SK_DES;
+                        skey.length = 8;
+                        break;
+                    default:
+                        skey.type = SK_GENERIC;
+                        skey.length = k5_session_key->length;
+                        encrypt_dont_support(ENCTYPE_DES_CFB64);
+                        encrypt_dont_support(ENCTYPE_DES_OFB64);
+                    }
+                    skey.data = k5_session_key->keyvalue.data;
+#else /* HEIMDAL */
+                    switch ( k5_session_key->enctype ) {
+                    case ENCTYPE_DES_CBC_CRC:
+                    case ENCTYPE_DES_CBC_MD5:
+                    case ENCTYPE_DES_CBC_MD4:
+                        skey.type = SK_DES;
+                        skey.length = 8;
+                    default:
+                        skey.type = SK_GENERIC;
+                        skey.length = k5_session_key->length;
+                        encrypt_dont_support(ENCTYPE_DES_CFB64);
+                        encrypt_dont_support(ENCTYPE_DES_OFB64);
+                    }
+                    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 <marc@mit.edu> 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 BETATEST
+            netclos();
+#endif /* 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 {
+#ifdef HEIMDAL
+                    switch ( k5_session_key->keytype ) {
+                    case ETYPE_DES_CBC_CRC:
+                    case ETYPE_DES_CBC_MD5:
+                    case ETYPE_DES_CBC_MD4:
+                        skey.type = SK_DES;
+                        skey.length = 8;
+                    default:
+                        skey.type = SK_GENERIC;
+                        skey.length = k5_session_key->length;
+                    }
+                    skey.data = k5_session_key->keyvalue.data;
+#else /* HEIMDAL */
+                    switch ( k5_session_key->enctype ) {
+                    case ENCTYPE_DES_CBC_CRC:
+                    case ENCTYPE_DES_CBC_MD5:
+                    case ENCTYPE_DES_CBC_MD4:
+                        skey.type = SK_DES;
+                        skey.length = 8;
+                        break;
+                    default:
+                        skey.type = SK_GENERIC;
+                        skey.length = k5_session_key->length;
+                    }
+                    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 = 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;
+            krb5_free_data_contents(k5_context,&msg);
+            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_const_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_cred(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;
+
+    hexdump("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);
+                hexdump("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);
+                hexdump("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);
+            krb5_free_data_contents(k5_context,&msg);
+        }
+#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
+                                  &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,UIDBUFLEN,name);
+                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;
+
+    hexdump("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;i<len;i++ ) {
+                if ( strTmp[i] == '\\' )
+                    strTmp[i] = '/';
+            }
+            if ( strTmp[len-1] != '/' )
+                ckstrncat(strTmp,"/tpasswd",sizeof(strTmp));
+            else
+                ckstrncat(strTmp,"tpasswd",sizeof(strTmp));
+            tpw = t_openpwbyname(strTmp);
+
+            ckstrncat(strTmp,".conf",sizeof(strTmp));
+            tconf = t_openconfbyname(strTmp);
+        }
+
+        if ( tpw && tconf )
+            ts = t_serveropenfromfiles(szUserNameRequested, tpw, tconf);
+        else
+            ts = t_serveropen(szUserNameRequested);
+        if ( tpw ) {
+            t_closepw(tpw);
+            tpw = NULL;
+        }
+        if ( tconf ) {
+            t_closeconf(tconf);
+            tconf = NULL;
+        }
+#else /* COMMENT */
+        ts = t_serveropen(szUserNameRequested);
+#endif /* COMMENT */
+#endif /* PRE_SRP_1_4_4 */
+
+        if( ts == NULL ) {
+            printf("User %s not found\r\n", szUserNameRequested);
+            SendSRPAuthSB(SRP_REJECT, (void *) "Password not set", -1);
+            return(AUTH_FAILURE);
+        }
+
+	pbuf = (char *)malloc(ts->n.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 */
+            {
+                hexdump("SRP_RESPONSE ts",ts,sizeof(ts));
+                hexdump("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 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 /* 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_count<KRB5_NUM_OF_ADDRS;addr_count++ )
+            if ( init->addrs[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;i<addr_count;i++,j++ ) {
+                addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
+                if (addrs[i] == NULL)
+                    goto exit_k5_init;
+
+                addrs[i]->magic = 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;i<addr_count;i++ ) {
+            if ( addrs[i] ) {
+                if ( addrs[i]->contents )
+                    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<num; i++)
+        printf("%c",c);
+}
+#endif /* KLIST */
+#endif /* KRB5 */
+
+#ifdef KRB4
+#define KDEBUG 1
+int k4debug = 0;                /* Kerberos 4 runtime debugging */
+
+#ifdef KINIT
+#define KRB_DEFAULT_LIFE 120 /* 10 hours in 5 minute intervals */
+
+#ifdef SNK4
+/* SNK4 is a hardware authentication system used to pre-authenticate    */
+/* a ticket getting ticket.  We do not support this code at the present */
+/* time in Kermit.                                                      */
+void
+get_input(s, size, stream)
+char *s;
+int size;
+FILE *stream;
+{
+    char *p;
+
+    if (fgets(s, size, stream) == NULL)
+        exit(1);
+    if ( (p = strchr(s, '\n')) != NULL)
+        *p = '\0';
+}
+#endif /* SNK4 */
+
+#ifdef COMMENT
+static char
+#ifdef CK_ANSIC
+hex_scan_nybble(char c)
+#else
+hex_scan_nybble(c) char c;
+#endif
+{
+    if (c >= '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);
+}
+
+#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;
+};
+
+static struct tkt_list_item * k4_tkt_list = NULL;
+
+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 */
+}
+
+static struct tkt_list_item * k5_tkt_list = NULL;
+
+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, k5_session_key->enctype,
+                                   &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;
+        krb5_int32 seqno=0;
+        krb5_int32 server_seqno=0;
+        char ** realmlist=NULL;
+        int buflen;
+        char tgt[256];
+
+        debug(F100,"ck_krb_rlogin version 5","",0);
+
+        realm = ck_krb5_realmofhost(hostname);
+        if (!realm) {
+            ckstrncpy(strTmp, "Can't find realm for host \"",AUTHTMPBL);
+            ckstrncat(strTmp, 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(term_speed)+strlen(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)),":",
+                  term_speed,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, 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)
+            get_cred->keyblock.enctype=ENCTYPE_DES_CBC_CRC;
+
+        /* 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,
+                                                 ENCTYPE_DES_CBC_CRC,
+#ifdef HEIMDAL
+                                                 ret_cred->session.keytype,
+#else /* HEIMDAL */
+                                                 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
+                               );
+        krb5_free_data_contents(k5_context,&cksumdat);
+
+        if (status) {
+            if ( !quiet )
+                printf("Couldn't authenticate to server: %s\r\n",
+                        error_message(status));
+            if (error) {
+                if ( !quiet ) {
+                    printf("Server returned error code %d (%s)\r\n",
+                        error->error,
+                        error_message(ERROR_TABLE_BASE_krb5 + error->error));
+                    if (error->text.length) {
+                        printf("Error text sent from server: %s\r\n",
+                                error->text.data);
+                    }
+                }
+                krb5_free_error(k5_context, error);
+                error = 0;
+            }
+            goto bad;
+        }
+
+        if (rep_ret) {
+            server_seqno = rep_ret->seq_number;
+            krb5_free_ap_rep_enc_part(k5_context, rep_ret);
+        }
+
+        (void) ttol(remoteuser, strlen(remoteuser)+1);
+        (void) ttol(term_speed, strlen(term_speed)+1);
+        (void) ttol(localuser, strlen(localuser)+1);
+
+        if (forward_flag) {   /* Forward credentials (global) */
+            if (status = krb5_fwd_tgt_creds( k5_context,
+                                             auth_context,
+                                             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(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, 
+                                    k5_session_key->enctype,
+                                    use_ivecs ? rd_len + 4 : rd_len,
+                                    &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, k5_session_key, 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);
+
+    hexdump("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 */
+    hexdump("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 */
+        hexdump("krb4_des_write garbage_buf",garbage_buf,8);
+    } else
+        hexdump("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 )
+        hexdump("krb4_des_write (post pcbc) garbage_buf",garbage_buf,8);
+    else
+        hexdump("krb4_des_write (post pcbc) buf",buf,8);
+    hexdump("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);
+    hexdump("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 <peter@runestig.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <time.h>
+#define Time_t time_t
+
+void
+XauDisposeAuth (auth)
+Xauth   *auth;
+{
+    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
+binaryEqual (a, b, len)
+register char   *a, *b;
+register int    len;
+{
+    while (len--)
+        if (*a++ != *b++)
+            return 0;
+    return 1;
+}
+
+#ifndef R_OK
+#define R_OK 04
+#endif /* R_OK */
+
+Xauth *
+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;
+{
+    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
+read_short (shortp, file)
+unsigned short  *shortp;
+FILE            *file;
+{
+    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
+read_counted_string (countp, stringp, file)
+unsigned short  *countp;
+char    **stringp;
+FILE    *file;
+{
+    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 *
+XauReadAuth (auth_file)
+FILE    *auth_file;
+{
+    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
+write_short (s, file)
+unsigned short  s;
+FILE            *file;
+{
+    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
+write_counted_string (count, string, file)
+unsigned short  count;
+char    *string;
+FILE    *file;
+{
+    if (write_short (count, file) == 0)
+        return 0;
+    if (fwrite (string, (int) sizeof (char), (int) count, file) != count)
+        return 0;
+    return 1;
+}
+
+int
+XauWriteAuth (auth_file, auth)
+FILE    *auth_file;
+Xauth   *auth;
+{
+    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 <tlyu@MIT.EDU>
+ *
+ * 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
+    if (k5_context)
+        krb5_init_ets(k5_context);
+#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
+auth_finished(result) int result; {
+    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;
+    }
+}
+#endif /* CK_SECURITY */
diff --git a/ckermit-8.0.211/ckuath.h b/ckermit-8.0.211/ckuath.h
new file mode 100644
index 0000000..0dbe8dc
--- /dev/null
+++ b/ckermit-8.0.211/ckuath.h
@@ -0,0 +1,228 @@
+/*  C K U A T H . H --  "C-Kermit to Authentication" interface  */
+
+/*
+  Author: Jeffrey E Altman <jaltman@secure-endpoints.com>,
+            Secure Endpoints Inc., New York City.
+
+  Copyright (C) 1999, 2004,
+    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
+
+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_encrypt_start, (VOID));
+_PROTOTYP(void ck_tn_encrypt_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.                                            */
+
+#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*/
diff --git a/ckermit-8.0.211/ckubwr.txt b/ckermit-8.0.211/ckubwr.txt
new file mode 100644
index 0000000..4b0d387
--- /dev/null
+++ b/ckermit-8.0.211/ckubwr.txt
@@ -0,0 +1,5330 @@
+
+                       C-Kermit 8.0 Unix Hints and Tips
+
+     Frank da Cruz
+     [1]The Kermit Project, [2]Columbia University
+
+   As of: C-Kermit 8.0.211 10 April 2004
+   This page last updated: Fri Apr 16 16:13:14 2004 (New York USA Time)
+
+     IF YOU ARE READING A PLAIN-TEXT version of this document, note it
+     is a plain-text dump of a Web page. You can visit the original (and
+     possibly more up-to-date) Web page here:
+
+  [3]http://www.columbia.edu/kermit/ckubwr.html
+
+     Since the material in this file has been accumulating since 1985,
+     some (much) of it might be dated. [4]Feedback from experts on
+     particular OS's and platforms is always welcome. 
+
+   [ [5]C-Kermit ] [ [6]Installation Instructions ] [ [7]TUTORIAL ]
+    ________________________________________________________________________
+
+  CONTENTS
+
+    1. [8]INTRODUCTION
+    2. [9]PREBUILT C-KERMIT BINARIES
+    3. [10]PLATFORM-SPECIFIC NOTES
+    4. [11]GENERAL UNIX-SPECIFIC LIMITATIONS AND BUGS
+    5. [12]INITIALIZATION AND COMMAND FILES
+    6. [13]COMMUNICATION SPEED SELECTION
+    7. [14]COMMUNICATIONS AND DIALING
+    8. [15]HARDWARE FLOW CONTROL
+    9. [16]TERMINAL CONNECTION AND KEY MAPPING
+   10. [17]FILE TRANSFER
+   11. [18]EXTERNAL FILE TRANSFER PROTOCOLS
+   12. [19]SECURITY
+   13. [20]MISCELLANEOUS USER REPORTS
+   14. [21]THIRD-PARTY DRIVERS
+
+   Quick Links:   [ [22]Linux ] [ [23]*BSD ] [[24]Mac OS X] [ [25]AIX ] [
+   [26]HP-UX ] [ [27]Solaris ] [ [28]SCO ] [ [29]DEC/Compaq ]
+    ________________________________________________________________________
+
+  1. INTRODUCTION
+
+   [ [30]Top ] [ [31]Contents ] [ [32]Next ]
+
+   SECTION CONTENTS
+
+  1.1. [33]Documentation
+  1.2. [34]Technical Support
+  1.3. [35]The Year 2000
+  1.4. [36]The Euro
+
+   THIS IS WHAT USED TO BE CALLED the "beware file" for the Unix version
+   of C-Kermit, previously distributed as ckubwr.txt and, before that, as
+   ckuker.bwr, after the fashion of old Digital Equipment Corporation
+   (DEC) software releases that came with release notes (describing what
+   had changed) and a "beware file" listing known bugs, limitations,
+   "non-goals", and things to watch out for. The C-Kermit beware file has
+   been accumulating since 1985, and it applies to many different
+   hardware platforms and operating systems, and many versions of them,
+   so it is quite large. Prior to C-Kermit 8.0, it was distributed only
+   in plain-text format. Now it is available as a Web document with
+   links, internal cross references, and so on, to make it easier to use.
+
+   This document applies to Unix C-Kermit in general, as well as to
+   specific Unix variations like [37]Linux, [38]AIX, [39]HP-UX,
+   [40]Solaris, and so on, and should be read in conjunction with the
+   [41]platform-independent C-Kermit beware file, which contains similar
+   information, but applying to all versions of C-Kermit (VMS, Windows,
+   OS/2, AOS/VS, VOS, etc, as well as to Unix).
+
+   There is much in this document that is (only) of historical interest.
+   The navigation links should help you skip directly to the sections
+   that are relevant to you. Numerous offsite Web links are supposed to
+   lead to further information but, as you know, Web links go stale
+   frequently and without warning. If you can supply additional,
+   corrected, updated, or better Web links, please feel free to [42]let
+   us know.
+
+  1.1. Documentation
+
+   [ [43]Top ] [ [44]Contents ] [ [45]Next ]
+
+   C-Kermit 6.0 is documented in the book [46]Using C-Kermit, Second
+   Edition, by Frank da Cruz and Christine M. Gianone, Digital Press,
+   Burlington, MA, USA, ISBN 1-55558-164-1 (1997), 622 pages. This
+   remains the definitive C-Kermit documentation. Until the third edition
+   is published (sorry, there is no firm timeframe for this), please also
+   refer to:
+
+   [47]Supplement to Using C-Kermit, Second Edition, For C-Kermit 7.0
+          Thorough documentation of features new to version 7.0.
+
+   [48]Supplement to Using C-Kermit, Second Edition, For C-Kermit 8.0
+          Thorough documentation of features new to version 8.0.
+
+  1.2. Technical Support
+
+   [ [49]Top ] [ [50]Contents ] [ [51]Section Contents ] [ [52]Next ] [
+   [53]Previous ]
+
+   For information on how to get technical support, please visit:
+
+    [54]http://www.columbia.edu/kermit/support.html
+
+  1.3. The Year 2000
+
+   [ [55]Top ] [ [56]Contents ] [ [57]Section Contents ] [ [58]Next ] [
+   [59]Previous ]
+
+   The Unix version of C-Kermit, release 6.0 and later, is "Year 2000
+   compliant", but only if the underlying operating system is too.
+   Contact your Unix operating system vendor to find out which operating
+   system versions, patches, hardware, and/or updates are required.
+   (Quite a few old Unixes are still in operation in the new millenium,
+   but with their date set 28 years in the past so at least the non-year
+   parts of the calendar are correct.)
+
+   As of C-Kermit 6.0 (6 September 1996), post-millenium file dates are
+   recognized, transmitted, received, and reproduced correctly during the
+   file transfer process in C-Kermit's File Attribute packets. If
+   post-millenium dates are not processed correctly on the other end,
+   file transfer still takes place, but the modification or creation date
+   of the received file might be incorrect. The only exception would be
+   if the "file collision update" feature is being used to prevent
+   unnecessary transfer of files that have not changed since the last
+   time a transfer took place; in this case, a file might be transferred
+   unnecessarily, or it might not be transferred when it should have
+   been. Correct operation of the update feature depends on both Kermit
+   programs having the correct date and time.
+
+   Of secondary importance are the time stamps in the transaction and/or
+   debug logs, and the date-related script programming constructs, such
+   as \v(date), \v(ndate), \v(day), \v(nday), and perhaps also the
+   time-related ones, \v(time) and \v(ntime), insofar as they might be
+   affected by the date. The \v(ndate) is a numeric-format date of the
+   form yyyymmdd, suitable for both lexical and numeric comparison and
+   sorting: e.g. 19970208 or 20011231. If the underlying operating system
+   returns the correct date information, these variables will have the
+   proper values. If not, then scripts that make decisions based on these
+   variables might not operate correctly.
+
+   Most date-related code is based upon the C Library asctime() string,
+   which always has a four-digit year. In Unix, the one bit of code in
+   C-Kermit that is an exception to this rule is several calls to
+   localtime(), which returns a pointer to a tm struct, in which the year
+   is presumed to be expressed as "years since 1900". The code depends on
+   this assumption. Any platforms that violate it will need special
+   coding. As of this writing, no such platforms are known.
+
+   Command and script programming functions that deal with dates use
+   C-Kermit specific code that always uses full years.
+
+  1.4. The Euro
+
+   [ [60]Top ] [ [61]Contents ] [ [62]Section Contents ] [ [63]Previous ]
+
+   C-Kermit 7.0 and later support Unicode (ISO 10646), ISO 8859-15 Latin
+   Alphabet 9, PC Code Page 858, Windows Code Pages 1250 and 1251, and
+   perhaps other character sets, that encode the Euro symbol, and can
+   translate among them as long as no intermediate character-set is
+   involved that does not include the Euro.
+    ________________________________________________________________________
+
+  2. PREBUILT C-KERMIT BINARIES
+
+   [ [64]Top ] [ [65]Contents ] [ [66]Next ] [ [67]Previous ]
+
+   It is often dangerous to run a binary C-Kermit (or any other) program
+   built on a different computer. Particularly if that computer had a
+   different C compiler, libraries, operating system version, processor
+   features, etc, and especially if the program was built with shared
+   libraries, because as soon as you update the libraries on your system,
+   they no longer match the ones referenced in the binary, and the binary
+   might refuse to load when you run it, in which case you'll see error
+   messages similar to:
+
+  Could not load program kermit
+  Member shr4.o not found or file not an archive
+  Could not load library libcurses.a[shr4.o]
+  Error was: No such file or directory
+
+   (These samples are from AIX.) To avoid this problem, we try to build
+   C-Kermit with statically linked libraries whenever we can, but this is
+   increasingly impossible as shared libraries become the norm.
+
+   It is often OK to run a binary built on an earlier OS version, but it
+   is rarely possible (or safe) to run a binary built on a later one, for
+   example to run a binary built under Solaris 8 on Solaris 2.6.
+   Sometimes even the OS-or-library patch/ECO level makes a difference.
+
+   A particularly insidious problem occurs when a binary was built on a
+   version of the OS that has patches from the vendor (e.g. to
+   libraries); in many cases you won't be able to run such a binary on an
+   unpatched version of the same platform.
+
+   When in doubt, build C-Kermit from the source code on the computer
+   where it is to be run (if possible!). If not, ask us for a binary
+   specific to your configuration. We might have one, and if we don't, we
+   might be able to find somebody who will build one for you.
+    ________________________________________________________________________
+
+  3. NOTES ON SPECIFIC UNIX VERSIONS
+
+   [ [68]Top ] [ [69]Contents ] [ [70]Next ] [ [71]Previous ]
+
+   SECTION CONTENTS
+
+  3.0.  [72]C-KERMIT ON PC-BASED UNIXES
+  3.1.  [73]C-KERMIT AND AIX
+  3.2.  [74]C-KERMIT AND HP-UX
+  3.3.  [75]C-KERMIT AND LINUX
+  3.4.  [76]C-KERMIT AND NEXTSTEP
+  3.5.  [77]C-KERMIT AND QNX
+  3.6.  [78]C-KERMIT AND SCO
+  3.7.  [79]C-KERMIT AND SOLARIS
+  3.8.  [80]C-KERMIT AND SUNOS
+  3.9.  [81]C-KERMIT AND ULTRIX
+  3.10. [82]C-KERMIT AND UNIXWARE
+  3.11. [83]C-KERMIT AND APOLLO SR10
+  3.12. [84]C-KERMIT AND TANDY XENIX 3.0
+  3.13. [85]C-KERMIT AND OSF/1 (DIGITAL UNIX) (TRU64 UNIX)
+  3.14. [86]C-KERMIT AND SGI IRIX
+  3.15. [87]C-KERMIT AND THE BEBOX
+  3.16. [88]C-KERMIT AND DG/UX
+  3.17. [89]C-KERMIT AND SEQUENT DYNIX
+  3.18. [90]C-KERMIT AND {FREE,OPEN,NET}BSD
+  3.19. [91]C-KERMIT AND MAC OS X
+  3.20. [92]C-KERMIT AND COHERENT
+
+   The following sections apply to specific Unix versions. Most of them
+   contain references to FAQs (Frequently Asked Questions), but these
+   tend to be ephemeral. For possibly more current information see:
+
+  [93]http://www.faqs.org
+  [94]http://aplawrence.com/Unixart/newtounix.html
+
+   One thread that runs through many of them, and implicitly perhaps
+   through all, concerns the problems that occur when trying to dial out
+   on a serial device that is (also) enabled for dialing in. The
+   "solutions" to this problem are many, varied, diverse, and usually
+   gross, involving configuring the device for bidirectional use. This is
+   done in a highly OS-dependent and often obscure manner, and the
+   effects (good or evil) are also highly dependent on the particular OS
+   (and getty variety, etc). Many examples are given in the
+   [95]OS-specific sections below.
+
+   An important point to keep in mind is that C-Kermit is a
+   cross-platform, portable software program. It was not designed
+   specifically and only for your particular Unix version, or for that
+   matter, for Unix in particular at all. It also runs on VMS, AOS/VS,
+   VOS, and other non-Unix platforms. All the Unix versions of C-Kermit
+   share common i/o modules, with compile-time #ifdef constructions used
+   to account for the differences among the many Unix products and
+   releases. If you think that C-Kermit is behaving badly or missing
+   something on your particular Unix version, you might be right -- we
+   can't claim to be expert in hundreds of different OS / version /
+   hardware / library combinations. If you're a programmer, take a look
+   at the source code and [96]send us your suggested fixes or changes. Or
+   else just [97]send us a report about what seems to be wrong and we'll
+   see what we can do.
+    ________________________________________________________________________
+
+  3.0. C-KERMIT ON PC-BASED UNIXES
+
+   [ [98]Top ] [ [99]Contents ] [ [100]Section Contents ] [ [101]Next ]
+
+   Also see: [102]http://www.pcunix.com/.
+
+   SECTION CONTENTS
+
+  3.0.1. [103]Interrupt Conflicts
+  3.0.2. [104]Windows-Specific Hardware
+  3.0.3. [105]Modems
+  3.0.4. [106]Character Sets
+  3.0.5. [107]Keyboard, Screen, and Mouse Access
+  3.0.6. [108]Laptops
+
+  3.0.1. Interrupt Conflicts
+
+   [ [109]Top ] [ [110]Contents ] [ [111]Section Contents ] [ [112]Next ]
+
+   PCs are not the best platform for real operating systems like Unix.
+   The architecture suffers from numerous deficiencies, not the least of
+   which is the stiflingly small number of hardware interrupts (either 7
+   or 15, many of which are preallocated). Thus adding devices, using
+   multiple serial ports, etc, is always a challenge and often a
+   nightmare. The free-for-all nature of the PC market and the lack of
+   standards combined with the diversity of Unix OS versions make it
+   difficult to find drivers for any particular device on any particular
+   version of Unix.
+
+   Of special interest to Kermit users is the fact that there is no
+   standard provision in the PC architecture for more than 2
+   communication (serial) ports. COM3 and COM4 (or higher) will not work
+   unless you (a) find out the hardware address and interrupt for each,
+   (b) find out how to provide your Unix version with this information,
+   and (c) actually set up the configuration in the Unix startup files
+   (or whatever other method is used). Watch out for interrupt conflicts,
+   especially when using a serial mouse, and don't expect to be able to
+   use more than two serial ports.
+
+   The techniques for resolving interrupt conflicts are different for
+   each operating system (Linux, NetBSD, etc). In general, there is a
+   configuration file somewhere that lists COM ports, something like
+   this:
+
+  com0    at isa? port 0x3f8 irq 4      # DOS COM1
+  com1    at isa? port 0x2f8 irq 3      # DOS COM2
+
+   The address and IRQ values in this file must agree with the values in
+   the PC BIOS and with the ports themselves, and there must not be more
+   than one device with the same interrupt. Unfortunately, due to the
+   small number of available interrupts, installing new devices on a PC
+   almost always creates a conflict. Here is a typical tale from a Linux
+   user (Fred Smith) about installing a third serial port:
+
+     ...problems can come from a number of causes. The one I fought with
+     for some time, and finally conquered, was that my modem is on an
+     add-in serial port, cua3/IRQ5. By default IRQ5 has a very low
+     priority, and does not get enough service in times when the system
+     is busy to prevent losing data. This in turn causes many resends.
+     There are two 'fixes' that I know of, one is to relax hard disk
+     interrupt hogging by using the correct parameter to hdparm, but I
+     don't like that one because the hdparm man page indicates it is
+     risky to use. The other one, the one I used, was to get 'irqtune'
+     and use it to give IRQ5 the highest priority instead of nearly the
+     lowest. Completely cured the problem.
+
+   Here's another one from a newsgroup posting:
+
+     After much hair pulling, I've discovered why my serial port won't
+     work. Apparently my [PC] has three serial devices (two comm ports
+     and an IR port), of which only two at a time can be active. I
+     looked in the BIOS setup and noticed that the IR port was
+     activated, but didn't realize at the time that this meant that COM2
+     was thereby de-activated. I turned off the IR port and now the
+     serial port works as advertised.
+    ________________________________________________________________________
+
+  3.0.2. Windows-Specific Hardware
+
+   [ [113]Top ] [ [114]Contents ] [ [115]Section Contents ] [ [116]Next ]
+   [ [117]Previous ]
+
+   To complicate matters, the PC platform is becoming increasingly and
+   inexorably Windows-oriented. More and more add-on devices are "Windows
+   only" -- meaning they are incomplete and rely on proprietary
+   Windows-based software drivers to do the jobs that you would expect
+   the device itself to do. PCMCIA, PCI, or "Plug-n-Play" devices are
+   rarely supported on PC-based Unix versions such as SCO; Winmodems,
+   Winprinters, and the like are not supported on any Unix variety (with
+   [118]a few exceptions). The self-proclaimed Microsoft PC 97 (or later)
+   standard only makes matters worse since its only purpose to ensure
+   that PCs are "optimized to run Windows 95 and Windows NT 4.0 and
+   future versions of these operating systems".
+
+   With the exception noted (the Lucent modem, perhaps a handful of
+   others by the time you read this), drivers for "Win" devices are
+   available only for Windows, since the Windows market dwarfs that of
+   any particular Unix brand, and for that matter all Unixes (or for that
+   matter, all non-Windows operating systems) combined. If your version
+   of Unix (SCO, Linux, BSDI, FreeBSD, etc) does not support a particular
+   device, then C-Kermit can't use it either. C-Kermit, like any Unix
+   application, must access all devices through drivers and not directly
+   because Unix is a real operating system.
+
+   Don't waste time thinking that you, or anybody else, could write a
+   Linux (or other Unix) driver for a Winmodem or other "Win" device.
+   First of all, these devices generally require realtime control, but
+   since Unix is a true multitasking operating system, realtime device
+   control is not possible outside the kernel. Second, the specifications
+   for these devices are secret and proprietary, and each one (and each
+   version of each one) is potentially different. Third, a Winmodem
+   driver would be enormously complex; it would take years to write and
+   debug, by which time it would be obsolete.
+
+   A more recent generation of PCs (circa 1999-2000) is marketed as
+   "Legacy Free". One can only speculate what that could mean. Most
+   likely it means it will ONLY run the very latest versions of Windows,
+   and is made exclusively of Winmodems, Winprinters, Winmemory, and
+   Win-CPU-fans (Legacy Free is a concept [119]pioneered by Microsoft).
+
+   Before you buy a new PC or add-on equipment, especially serial ports,
+   internal modems, or printers, make sure they are compatible with your
+   version of Unix. This is becoming an ever-greater challenge; only a
+   huge company like Microsoft can afford to be constantly cranking out
+   and/or verifying drivers for the thousands of video boards, sound
+   cards, network adapters, SCSI adapters, buses, etc, that spew forth in
+   an uncontrolled manner from all corners of the world on a daily basis.
+   With very few exceptions, makers of PCs assemble the various
+   components and then verify them only with Windows, which they must do
+   since they are, no doubt, preloading the PC with Windows. To find a
+   modern PC that is capable of running a variety of non-Windows
+   operating systems (e.g. Linux, SCO OpenServer, Unixware, and Solaris)
+   is a formidable challenge requiring careful study of each vendor's
+   "compatibility lists" and precise attention to exact component model
+   numbers and revision levels.
+    ________________________________________________________________________
+
+  3.0.3. Modems
+
+   [ [120]Top ] [ [121]Contents ] [ [122]Section Contents ] [ [123]Next ]
+   [ [124]Previous ]
+
+   External modems are recommended:
+
+     * They don't need any special drivers.
+     * You can use the lights and speaker to troubleshoot dialing.
+     * You can share them among all types of computers.
+     * You can easily turn them off and on when power-cycling seems
+       warranted.
+     * They are more likely to have manuals.
+
+   Internal PC modems (even when they are not Winmodems, which is
+   increasingly unlikely in new PCs) are always trouble, especially in
+   Unix. Even when they work for dialing out, they might not work for
+   dialing in, etc. Problems that occur when using an internal modem can
+   almost always be eliminated by switching to an external one. Even when
+   an internal modem is not a Winmodem or Plug-n-Play, it is often a
+   no-name model of unknown quality -- not the sort of thing you want
+   sitting directly on your computer's bus. (Even if it does not cause
+   hardware problems, it probably came without a command list, so no Unix
+   software will know how to control it.) For more about Unix compatible
+   modems, see:
+
+  [125]http://www.idir.net/~gromitkc/winmodem.html
+
+   Remember that PCs, even now -- more than two decades after they were
+   first introduced -- are not (in general) capable of supporting more
+   than 2 serial devices. Here's a short success story from a recent
+   newsgroup posting: "I have a Diamond SupraSonic II dual modem in my
+   machine. What I had to end up doing is buying a PS/2 mouse and port
+   and install it. Had to get rid of my serial mouse. I also had to
+   disable PnP in my computer bios. I was having IRQ conflicts between my
+   serial mouse and 'com 3'. Both modems work fine for me. My first modem
+   is ttyS0 and my second is ttyS1." Special third-party multiport boards
+   such as [126]DigiBoard are available for certain Unix platforms
+   (typically SCO, maybe Linux) that come with special platform-specific
+   drivers.
+    ________________________________________________________________________
+
+  3.0.4. Character Sets
+
+   [ [127]Top ] [ [128]Contents ] [ [129]Section Contents ] [ [130]Next ]
+   [ [131]Previous ]
+
+   PCs generally have PC code pages such as CP437 or CP850, and these are
+   often used by PC-based Unix operating systems, particularly on the
+   console. These are supported directly by C-Kermit's SET FILE
+   CHARACTER-SET and SET TERMINAL CHARACTER-SET commands. Some PC-based
+   Unix versions, such as recent Red Hat Linux releases, might also
+   support Microsoft Windows code pages such as CP1252, or even Latin
+   Alphabet 1 itself (perhaps displayed with CP437 glyphs). (And work is
+   in progress to support Unicode UTF8 in Linux.)
+
+   Certain Windows code pages are not supported directly by C-Kermit, but
+   since they are ISO Latin Alphabets with nonstandard "extensions" in
+   the C1 control range, you can substitute the corresponding Latin
+   alphabet (or other character set) in any C-Kermit character-set
+   related commands:
+
+  Windows Code Page    Substitution
+   CP 1004              Latin-1
+   CP 1051              HP Roman-8
+
+   Other Windows code pages are mostly (or totally) incompatible with
+   their Latin Alphabet counterparts (e.g. CP1250 and Latin-2), and
+   several of these are already supported by C-Kermit 7.0 and later
+   (1250, 1251, and 1252).
+    ________________________________________________________________________
+
+  3.0.5. Keyboard, Screen, and Mouse Access
+
+   [ [132]Top ] [ [133]Contents ] [ [134]Section Contents ] [ [135]Next ]
+   [ [136]Previous ]
+
+   Finally, note that as a real operating system, Unix (unlike Windows)
+   does not provide the intimate connection to the PC keyboard, screen,
+   and mouse that you might expect. Unix applications can not "see" the
+   keyboard, and therefore can not be programmed to understand F-keys,
+   Editing keys, Arrow keys, Alt-key combinations, and the like. This is
+   because:
+
+    a. Unix is a portable operating system, not only for PCs;
+    b. Unix sessions can come from anywhere, not just the PC's own
+       keyboard and screen; and:
+    c. even though it might be possible for an application that actually
+       is running on the PC's keyboard and screen to access these devices
+       directly, there are no APIs (outside of X) for this.
+    ________________________________________________________________________
+
+  3.0.6. Laptops
+
+   [ [137]Top ] [ [138]Contents ] [ [139]Section Contents ] [
+   [140]Previous ]
+
+   (To be filled in . . .)
+    ________________________________________________________________________
+
+  3.1. C-KERMIT AND AIX
+
+   [ [141]Top ] [ [142]Contents ] [ [143]Section Contents ] [ [144]Next ]
+   [ [145]Previous ]
+
+   SECTION CONTENTS
+
+  3.1.1. [146]AIX: General
+  3.1.2. [147]AIX: Network Connections
+  3.1.3. [148]AIX: Serial Connections
+  3.1.4. [149]AIX: File Transfer
+  3.1.5. [150]AIX: Xterm Key Map
+
+   For additional information see:
+     * [151]http://www.emerson.emory.edu/services/aix-faq/
+     * [152]http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.aix.html
+     * [153]http://www.cis.ohio-state.edu/hypertext/faq/usenet/aix-faq/to
+       p.html
+     * [154]http://aixpdslib.seas.ucla.edu/
+     * [155]http://www.rootvg.net (AIX history)
+     * [156]ftp://rtfm.mit.edu/pub/usenet/news.answers/aix-faq/part1
+     * [157]ftp://mirrors.aol.com/pub/rtfm/usenet-by-hierarchy/comp/unix/
+       aix
+
+   and/or read the [158]comp.unix.aix newsgroup.
+      ______________________________________________________________________
+
+    3.1.1. AIX: General
+
+   [ [159]Top ] [ [160]Contents ] [ [161]Section Contents ] [ [162]Next ]
+
+   About AIX version numbers: "uname -a" tells the two-digit version
+   number, such as 3.2 or 4.1. The three-digit form can be seen with the
+   "oslevel" command (this information is unavailable at the API level
+   and is reportedly obtained by scanning the installed patch list).
+   Supposedly all three-digit versions within the same two-digit version
+   (e.g. 4.3.1, 4.3.2) are binary compatible; i.e. a binary built on any
+   one of them should run on all others, but who knows. Most AIX
+   advocates tell you that any AIX binary will run on any AIX version
+   greater than or equal to the one under which it was built, but
+   experience with C-Kermit suggests otherwise. It is always best to run
+   a binary built under your exact same AIX version, down to the third
+   decimal place, if possible. Ideally, build it from source code
+   yourself. Yes, this advice would be easier to follow if AIX came with
+   a C compiler.
+      ______________________________________________________________________
+
+    3.1.2. AIX: Network Connections
+
+   [ [163]Top ] [ [164]Contents ] [ [165]Section Contents ] [ [166]Next ]
+   [ [167]Previous ]
+
+   File transfers into AIX 4.2 or 4.3 through the AIX Telnet or Rlogin
+   server have been observed to fail (or accumulate huge numbers of
+   correctable errors, or even disconnect the session), when exactly the
+   same kind of transfers into AIX 4.1 work without incident, as do such
+   transfers into all non-AIX platforms on the same kind of connections
+   (with a few exceptions noted elsewhere in this document). AIX 4.3.3
+   seems to be particularly fragile in this regard; the weakness seems to
+   be in its pseudoterminal (pty) driver. High-speed streaming transfers
+   work perfectly, however, if the AIX Telnet server and pty driver are
+   removed from the picture; e.g, by using "set host * 3000" on AIX.
+
+   The problem can be completely cured by replacing the IBM Telnet server
+   with [168]MIT's Kerberos Telnet server -- even if you don't actually
+   use the Kerberos part. Diagnosis: AIX pseudoterminals (which are
+   controlled by the Telnet server to give you a login terminal for your
+   session) have quirks that not even IBM knows about. The situation with
+   AIX 5.x is not known, but if it has the same problem, the same cure is
+   available.
+
+   Meanwhile, the only remedy when going through the IBM Telnet server is
+   to cut back on Kermit's performance settings until you find a
+   combination that works:
+
+     * SET STREAMING OFF
+     * SET WINDOW-SIZE small-number
+     * SET { SEND, RECEIVE } PACKET-LENGTH small-number
+     * SET PREFIXING { CAUTIOUS, ALL }
+
+   In some cases, severe cutbacks are required, e.g. those implied by the
+   ROBUST command. Also be sure that the AIX C-Kermit on the remote end
+   has "set flow none" (which is the default). NOTE: Maybe this one can
+   also be addressed by starting AIX telnetd with the "-a" option. The
+   situation with SSH connections is not known, but almost certainly the
+   same.
+
+   When these problems occur, the system error log contains:
+
+  LABEL:          TTY_TTYHOG
+  IDENTIFIER:     0873CF9F
+  Type:           TEMP
+  Resource Name:  pts/1
+
+  Description
+  TTYHOG OVER-RUN
+
+  Failure Causes
+  EXCESSIVE LOAD ON PROCESSOR
+
+  Recommended Actions
+  REDUCE SYSTEM LOAD.
+  REDUCE SERIAL PORT BAUD RATE
+
+   Before leaving the topic of AIX pseudoterminals, it is very likely
+   that Kermit's PTY and SSH commands do not work well either, for the
+   same reason that Telnet connections into AIX don't work well. A brief
+   test with "pty rlogin somehost" got a perfectly usable terminal
+   (CONNECT) session, but file-transfer problems like those just
+   described.
+
+   Reportedly, telnet from AIX 4.1-point-something to non-Telnet ports
+   does not work unless the port number is in the /etc/services file;
+   it's not clear from the report whether this is a problem with AIX
+   Telnet (in which case it would not affect Kermit), or with the sockets
+   library (in which case it would). The purported fix is IBM APAR
+   IX61523.
+
+   C-Kermit SET HOST or TELNET from one AIX 3.1 (or earlier) system to
+   another won't work right unless you set your local terminal type to
+   something other than AIXTERM. When your terminal type is AIXTERM, AIX
+   TELNET sends two escapes whenever you type one, and the AIX telnet
+   server swallows one of them. This has something to do with the "hft"
+   device. This behavior seems to be removed in AIX 3.2 and later.
+      ______________________________________________________________________
+
+    3.1.3. AIX: Serial Connections
+
+   [ [169]Top ] [ [170]Contents ] [ [171]Section Contents ] [ [172]Next ]
+   [ [173]Previous ]
+
+   In AIX 3, 4, or 5, C-Kermit won't be able to "set line /dev/tty0" (or
+   any other dialout device) if you haven't installed "cu" or "uucp" on
+   your system, because installing these is what creates the UUCP
+   lockfile directory. If SET LINE commands always result in "Sorry,
+   access to lock denied", even when C-Kermit has been given the same
+   owner, group, and permissions as cu:
+
+  -r-sr-xr-x   1 uucp     uucp       67216 Jul 27 1999  cu
+
+   and even when you run it as root, then you must go back and install
+   "cu" from your AIX installation media.
+
+   According to IBM's "From Strength to Strength" document (21 April
+   1998), in AIX 4.2 and later "Async supports speeds on native serial
+   ports up to 115.2kbps". However, no API is documented to achieve
+   serial speeds higher than 38400 bps. Apparently the way to do this --
+   which might or might not work only on the IBM 128-port multiplexer --
+   is:
+
+  cxma-stty fastbaud /dev/tty0
+
+   which, according to "man cxma-stty":
+
+     fastbaud Alters the baud rate table, so 50 baud becomes 57600 baud.
+     -fastbaud Restores the baud rate table, so 57600 baud becomes 50
+     baud.
+
+   Presumably (but not certainly) this extrapolates to 110 "baud" becomes
+   76800 bps, and 150 becomes 115200 bps. So to use high serial speeds in
+   AIX 4.2 or 4.3, the trick would be to give the "cxma-stty fastbaud"
+   command for the desired tty device before starting Kermit, and then
+   use "set speed 50", "set speed 110", or "set speed 150" to select
+   56700, 76800, or 115200 bps. It is not known whether cxma-stty
+   requires privilege.
+
+   According to one report, "Further investigation with IBM seems to
+   indicate that the only hardware capable of doing this is the 128-port
+   multiplexor with one (or more) of the 16 port breakout cables
+   (Enhanced Remote Async Node 16-Port EIA-232). We are looking at about
+   CDN$4,000 in hardware just to hang a 56kb modem on there. Of course,
+   we can then hang 15 more, if we want. This hardware combo is described
+   to be good to 230.4kbps."
+
+   Another report says (quote from AIX newsgroup, March 1999):
+
+     The machine type and the adapter determine the speed that one can
+     actually run at. The older microchannel machines have much slower
+     crystal frequencies and may not go beyond 76,800. A feature put
+     into AIX 421 allows one to key in non-POSIX baud rates and if the
+     uart can support that speed, it will get set. this applies also to
+     43p's and beyond. 115200 is the max for the 43P's native serial
+     port. As crytal frequencies continue to increase, the built-in
+     serial ports speeds will improve. To use 'uucp' or 'ate' at the
+     higher baud rates, configure the port for the desired speed, but
+     set the speed of uucp or ate to 50. Any non-POSIX speeds set in the
+     ttys configuration will the be used. In the case of the 128-port
+     adapters or the ISA 8-port or PCI 8-port adapter, there are only a
+     few higher baud rates.
+
+    a. Change the port to enable high baud rates:
+          + B50 for 57600
+          + B75 for 76800
+          + B110 for 115200
+          + B200 for 230000
+    b. chdev -l ttyX -a fastbaud=enable
+          + For the 128 ports original style rans, only 57600 bps is
+            supported.
+          + For the new enhanced RANs, up to 230Kbps is supported.
+
+   In AIX 2.2.1 on the RT PC with the 8-port multiplexer, SET SPEED 38400
+   gives 9600 bps, but SET SPEED 19200 gives 19200 (on the built-in S1
+   port).
+
+   Note that some RS/6000s (e.g. the IBM PowerServer 320) have
+   nonstandard rectangular 10-pin serial ports; the DB-25 connector is
+   NOT a serial port; it is a parallel printer port. IBM cables are
+   required for the serial ports, (The IBM RT PC also had rectangular
+   serial ports -- perhaps the same as these, perhaps different.)
+
+   If you dial in to AIX through a modem that is connected directly to an
+   AIX port (e.g. on the 128-port multiplexer) and find that data is
+   lost, especially when uploading files to the AIX system (and system
+   error logs report buffer overruns on the port):
+
+    1. Make sure the port and modem are BOTH configured for hardware
+       (RTS/CTS) flow control. The port is configured somewhere in the
+       system configuration, outside of Kermit.
+    2. Tell C-Kermit to "set flow keep"; experimentation shows that SET
+       FLOW RTS/CTS has no effect when used in remote mode (i.e. on
+       /dev/tty, as opposed to a specify port device).
+    3. Fixes for bugs in the original AIX 4.2 tty (serial i/o) support
+       and other AIX bugs are available from IBM at:
+  [174]http://service.software.ibm.com/rs6000/
+       Downloads -> Software Fixes -> Download FixDist gets an
+       application for looking up known problems.
+
+   Many problems reported with bidirectional terminal lines on AIX 3.2.x
+   on the RS/6000. Workaround: don't use bidirectional terminal lines, or
+   write a shell-script wrapper for Kermit that turns getty off on the
+   line before starting Kermit, or before Kermit attempts to do the SET
+   LINE. (But note: These problems MIGHT be fixed in C-Kermit 6.0 and
+   later.) The commands for turning getty off and on (respectively) are
+   /usr/sbin/pdisable and /usr/sbin/penable.
+      ______________________________________________________________________
+
+    3.1.4. AIX: File Transfer
+
+   [ [175]Top ] [ [176]Contents ] [ [177]Section Contents ] [ [178]Next ]
+   [ [179]Previous ]
+
+   Evidently AIX 4.3 (I don't know about earlier versions) does not allow
+   open files to be overwritten. This can cause Kermit transfers to fail
+   when FILE COLLISION is OVERWRITE, where they might work on other Unix
+   varieties or earlier AIX versions.
+
+   Transfer of binary -- and maybe even text -- files can fail in AIX if
+   the AIX terminal has particular port can have character-set
+   translation done for it by the tty driver. The following advice from a
+   knowledgeable AIX user:
+
+     [This feature] has to be checked (and set/cleared) with a separate
+     command, unfortunately stty doesn't handle this. To check:
+
+  $ setmaps
+  input map: none installed
+  output map: none installed
+
+     If it says anything other than "none installed" for either one, it
+     is likely to cause a problem with kermit. To get rid of installed
+     maps:
+
+  $ setmaps -t NOMAP
+
+     However, I seem to recall that with some versions of AIX before
+     3.2.5, only root could change the setting. I'm not sure what
+     versions - it might have only been under AIX 3.1 that this was
+     true. At least with AIX 3.2.5 an ordinary user can set or clear the
+     maps.
+
+   On the same problem, another knowledgeable AIX user says:
+
+     The way to get information on the NLS mapping under AIX (3.2.5
+     anyway) is as follows. From the command line type:
+
+  lsattr -l tty# -a imap -a omap -E -H
+
+     Replace the tty number for the number sign above. This will give a
+     human readable output of the settings that looks like this;
+
+  # lsattr -l tty2 -a imap -a omap -E -H
+  attribute value description     user_settable
+
+  imap      none  INPUT map file  True
+  omap      none  OUTPUT map file True
+
+     If you change the -H to a -O, you get output that can easily be
+     processed by another program or a shell script, for example:
+
+  # lsattr -l tty2 -a imap -a omap -E -O
+  #imap:omap
+  none:none
+
+     To change the settings from the command line, the chdev command is
+     used with the following syntax.
+
+  chdev -l tty# -a imap='none' -a omap='none'
+
+     Again substituting the appropriate tty port number for the number
+     sign, "none" being the value we want for C-Kermit. Of course, the
+     above can also be changed by using the SMIT utility and selecting
+     devices - tty. (...end quote)
+      ______________________________________________________________________
+
+    3.1.5. AIX: Xterm Key Map
+
+   [ [180]Top ] [ [181]Contents ] [ [182]Section Contents ] [
+   [183]Previous ]
+
+   Here is a sample configuration for setting up an xterm keyboard for
+   VT220 or higher terminal emulation on AIX, courtesy of Bruce Momjian,
+   Drexel Hill, PA. Xterm can be started like this:
+
+  xterm $XTERMFLAGS +rw +sb +ls $@ -tm 'erase ^? intr ^c' -name vt220 \
+          -title vt220 -tn xterm-220 "$@" &
+
+---------------------------------------------------------------------------
+  XTerm*VT100.Translations: #override \n\
+          <Key>Home: string(0x1b) string("[3~") \n \
+          <Key>End: string(0x1b) string("[4~") \n
+  vt220*VT100.Translations: #override \n\
+  Shift   <Key>F1: string("[23~") \n \
+  Shift   <Key>F2: string("[24~") \n \
+  Shift   <Key>F3: string("[25~") \n \
+  Shift   <Key>F4: string("[26~") \n \
+  Shift   <Key>F5: string("[K~") \n \
+  Shift   <Key>F6: string("[31~") \n \
+  Shift   <Key>F7: string("[31~") \n \
+  Shift   <Key>F8: string("[32~") \n \
+  Shift   <Key>F9: string("[33~") \n \
+  Shift   <Key>F10: string("[34~") \n \
+  Shift   <Key>F11: string("[28~") \n \
+  Shift   <Key>F12: string("[29~") \n \
+          <Key>Print: string(0x1b) string("[32~") \n\
+          <Key>Cancel: string(0x1b) string("[33~") \n\
+          <Key>Pause: string(0x1b) string("[34~") \n\
+          <Key>Insert: string(0x1b) string("[2~") \n\
+          <Key>Delete: string(0x1b) string("[3~") \n\
+          <Key>Home: string(0x1b) string("[1~") \n\
+          <Key>End: string(0x1b) string("[4~") \n\
+          <Key>Prior: string(0x1b) string("[5~") \n\
+          <Key>Next: string(0x1b) string("[6~") \n\
+          <Key>BackSpace: string(0x7f) \n\
+          <Key>Num_Lock: string(0x1b) string("OP") \n\
+          <Key>KP_Divide: string(0x1b) string("Ol") \n\
+          <Key>KP_Multiply: string(0x1b) string("Om") \n\
+          <Key>KP_Subtract: string(0x1b) string("OS") \n\
+          <Key>KP_Add: string(0x1b) string("OM") \n\
+          <Key>KP_Enter: string(0x1b) string("OM") \n\
+          <Key>KP_Decimal: string(0x1b) string("On") \n\
+          <Key>KP_0: string(0x1b) string("Op") \n\
+          <Key>KP_1: string(0x1b) string("Oq") \n\
+          <Key>KP_2: string(0x1b) string("Or") \n\
+          <Key>KP_3: string(0x1b) string("Os") \n\
+          <Key>KP_4: string(0x1b) string("Ot") \n\
+          <Key>KP_5: string(0x1b) string("Ou") \n\
+          <Key>KP_6: string(0x1b) string("Ov") \n\
+          <Key>KP_7: string(0x1b) string("Ow") \n\
+          <Key>KP_8: string(0x1b) string("Ox") \n\
+          <Key>KP_9: string(0x1b) string("Oy") \n
+
+  !       <Key>Up: string(0x1b) string("[A") \n\
+  !       <Key>Down: string(0x1b) string("[B") \n\
+  !       <Key>Right: string(0x1b) string("[C") \n\
+  !       <Key>Left: string(0x1b) string("[D") \n\
+
+  *visualBell:    true
+  *saveLines:     1000
+  *cursesemul:    true
+  *scrollKey:     true
+  *scrollBar:     true
+    ________________________________________________________________________
+
+  3.2. C-KERMIT AND HP-UX
+
+   [ [184]Top ] [ [185]Contents ] [ [186]Section Contents ] [ [187]Next ]
+   [ [188]Previous ]
+
+   SECTION CONTENTS
+
+  3.2.0. [189]Common Problems
+  3.2.1. [190]Building C-Kermit on HP-UX
+  3.2.2. [191]File Transfer
+  3.2.3. [192]Dialing Out and UUCP Lockfiles in HP-UX
+  3.2.4. [193]Notes on Specific HP-UX Releases
+  3.2.5. [194]HP-UX and X.25
+
+   REFERENCES
+
+   For further information, read the [195]comp.sys.hp.hpux newsgroup.
+
+   C-Kermit is included as part of the HP-UX operating system by contract
+   between Hewlett Packard and Columbia University for HP-UX 10.00 and
+   later. Each level of HP-UX includes a freshly built C-Kermit binary in
+   /bin/kermit, which should work correctly. Binaries built for regular
+   HP-UX may be used on Trusted HP-UX and vice-versa, except for use as
+   IKSD because of the different authentication methods.
+
+   Note that HP does not update C-Kermit versions for any but its most
+   current HP-UX release. So, for example, HP-UX 10.20 has C-Kermit 6.0;
+   11.00 has C-Kermit 7.0, and 11.22 has 8.0. Of course, as with all
+   software, older Kermit versions have bugs (such as buffer overflow
+   vulnerabilities) that are fixed in later versions. From time to time,
+   HP discovers one of these (long-ago fixed) bugs and issues a security
+   alert for the older OS's, recommending some draconian measure to avoid
+   the problem. The true fix in each situation is to install the current
+   release of C-Kermit.
+
+  3.2.0. Common Problems
+
+   [ [196]Top ] [ [197]Contents ] [ [198]Section Contents ] [ [199]Next ]
+
+   Some HP workstations have a BREAK/RESET key. If you hit this key while
+   C-Kermit is running, it might kill or suspend the C-Kermit process.
+   C-Kermit arms itself against these signals, but evidently the
+   BREAK/RESET key is -- at least in some circumstances, on certain HP-UX
+   versions -- too powerful to be caught. (Some report that the first
+   BREAK/RESET shows up as SIGINT and is caught by C-Kermit's former
+   SIGINT handler even when SIGINT is currently set to SIG_IGN; the
+   second kills Kermit; other reports suggest the first BREAK/RESET sends
+   a SIGTSTP (suspend signal) to Kermit, which it catches and suspends
+   itself. You can tell C-Kermit to ignore suspend signals with SET
+   SUSPEND OFF. You can tell C-Kermit to ignore SIGINT with SET COMMAND
+   INTERRUPTION OFF. It is not known whether these commands also grant
+   immunity to the BREAK/RESET key (one report states that with SET
+   SUSPEND OFF, the BREAK/RESET key is ignored the first four times, but
+   kills Kermit the 5th time). In any case:
+
+    1. If this key is mapped to SIGINT or SIGTSTP, C-Kermit catches or
+       ignores it, depending on which mode (CONNECT, command, etc) Kermit
+       is in.
+    2. If it causes HP-UX to kill C-Kermit, there is nothing C-Kermit can
+       do to prevent it.
+
+   When HP-UX is on the remote end of the connection, it is essential
+   that HP-UX C-Kermit be configured for Xon/Xoff flow control (this is
+   the default, but in case you change it and then experience
+   file-transfer failures, this is a likely reason).
+    ________________________________________________________________________
+
+  3.2.1. Building C-Kermit on HP-UX
+
+   [ [200]Top ] [ [201]Contents ] [ [202]Section Contents ] [ [203]Next ]
+   [ [204]Previous ]
+
+     This section applies mainly to old (pre-10.20) HP-UX version on
+     old, slow, and/or memory-constrained hardware.
+
+   During the C-Kermit 6.0 Beta cycle, something happened to ckcpro.w
+   (or, more precisely, the ckcpro.c file that is generated from it)
+   which causes HP optimizing compilers under HP-UX versions 7.0 and 8.0
+   (apparently on all platforms) as well as under HP-UX 9.0 on Motorola
+   platforms only, to blow up. In versions 7.0 and 8.0 the problem has
+   spread to other modules.
+
+   The symptoms vary from the system grinding to a halt, to the compiler
+   crashing, to the compilation of the ckcpro.c module taking very long
+   periods of time, like 9 hours. This problem is handled by compiling
+   the modules that tickle it without optimization; the new C-Kermit
+   makefile takes care of this, and shows how to do it in case the same
+   thing begins happening with other modules.
+
+   On HP-UX 9.0, a kernel parameter, maxdsiz (maximum process data
+   segment size), seems to be important. On Motorola systems, it is 16MB
+   by default, whereas on RISC systems the default is much bigger.
+   Increasing maxdsiz to about 80MB seems to make the problem go away,
+   but only if the system also has a lot of physical memory -- otherwise
+   it swaps itself to death.
+
+   The optimizing compiler might complain about "some optimizations
+   skipped" on certain modules, due to lack of space available to the
+   optimizer. You can increase the space (the incantation depends on the
+   particular compiler version -- see the [205]makefile), but doing so
+   tends to make the compilations take a much longer time. For example,
+   the "hpux0100o+" makefile target adds the "+Onolimit" compiler flag,
+   and about an hour to the compile time on an HP-9000/730. But it *does*
+   produce an executable that is about 10K smaller :-)
+
+   In the makefile, all HP-UX entries automatically skip optimization of
+   problematic modules.
+    ________________________________________________________________________
+
+  3.2.2. File Transfer
+
+   [ [206]Top ] [ [207]Contents ] [ [208]Section Contents ] [ [209]Next ]
+   [ [210]Previous ]
+
+   Telnet connections into HP-UX versions up to and including 11.11 (and
+   possibly 11.20) tend not to lend themselves to file transfer due to
+   limitations, restrictions, and/or bugs in the HP-UX Telnet server
+   and/or pseudoterminal (pty) driver.
+
+   In C-Kermit 6.0 (1996) an unexpected slowness was noted when
+   transferring files over local Ethernet connections when an HP-UX
+   system (9.05 or 10.00) was on the remote end. The following experiment
+   was conducted to determine the cause. C-Kermit 6.0 was used; the
+   situation is slightly better using C-Kermit 7.0's streaming feature
+   and HP-UX 10.20 on the far end.
+
+   The systems were HP-UX 10.00 (on 715/33) and SunOS 4.1.3 (on
+   Sparc-20), both on the same local 10Mbps Ethernet, packet length 4096,
+   parity none, control prefixing "cautious", using only local disks on
+   each machine -- no NFS. In the C-Kermit 6.0 (ACK/NAK) case, the window
+   size was 20; in the streaming case there is no window size (i.e. it is
+   infinite). The test file was C-Kermit executable, transferred in
+   binary mode. Conditions were relatively poor: the Sun and the local
+   net heavily loaded; the HP system is old, slow, and
+   memory-constrained.
+
+                   C-Kermit 6.0...    C-Kermit 7.0...
+ Local    Remote   ACK/NAK........    Streaming......
+ Client   Server   Send    Receive    Send    Receive
+  Sun      HP       36       18        64       18
+  HP       HP       25       15        37       16
+  HP       Sun      77       83       118       92
+  Sun      Sun      60       60       153      158
+
+   So whenever HP is the remote we have poor performance. Why?
+
+     * Changing file display to CRT has no effect (so it's not the curses
+       library on the client side).
+     * Changing TCP RECV-BUFFER or SEND-BUFFER has little effect.
+     * Telling the client to make a binary-mode connection (SET TELNET
+       BINARY REQUESTED, which successfully negotiates a binary
+       connection) has no effect on throughput.
+
+   BUT... If I start HP-UX C-Kermit as a TCP service:
+
+  set host * 3000
+  server
+
+   and then from the client "set host xxx 3000", I get:
+
+                   C-Kermit 6.0...    C-Kermit 7.0...
+ Local    Remote   ACK/NAK........    Streaming......
+ Client   Server   Send    Receive    Send    Receive
+  Sun      HP       77       67       106      139
+  HP       HP       50       50        64       62
+  HP       Sun      57       85       155      105
+  Sun      Sun      57       50       321      314
+
+   Therefore the HP-UX telnet server or pty driver seems to be adding
+   more overhead than the SunOS one, and most others. When going through
+   this type of connection (a remote telnet server) there is little
+   Kermit can do improve matters, since the telnet server and pty driver
+   are between the two Kermits, and neither Kermit program can have any
+   influence over them (except putting the Telnet connection in binary
+   mode, but that doesn't help).
+
+   (The numbers for the HP-HP transfers are lower than the others since
+   both Kermit processes are running on the same slow 33MHz CPU.)
+
+   Matters seem to have deteriorated in HP-UX 11. Now file transfers over
+   Telnet connections fail completely, rather than just being slow. In
+   the following trial, a Telnet connection was made from Kermit 95 to
+   HP-UX 11.11 on an HP-9000/785/B2000 over local 10Mbps Ethernet running
+   C-Kermit 8.00 in server mode (under the HP-UX Telnet server):
+
+                   Text........    Binary......
+  Stream  Pktlen   GET     SEND    GET     SEND
+    On     4000    Fail    Fail    Fail    Fail
+    Off    4000    Fail    Fail    Fail    Fail
+    Off    2000    OK      Fail    OK      Fail
+    On     2000    OK      Fail    OK      Fail
+    On     3000    Fail    Fail    Fail    Fail
+    On     2500    Fail    Fail    Fail    Fail
+    On     2047    OK      Fail    OK      Fail
+    On     2045    OK      Fail    OK      Fail
+    Off     500    OK      OK      OK      OK
+    On      500    OK      Fail    OK      Fail
+    On      240    OK      Fail    OK      Fail
+
+   As you can see, downloads are problematic unless the receiver's Kermit
+   packet length is 2045 or less, but uploads work only with streaming
+   disabled and the packet length restricted to 500. To force file
+   transfers to work on this connection, the desktop Kermit must be told
+   to:
+
+  set streaming off
+  set receive packet-length 2000
+  set send packet-length 500
+
+   However, if a connection is made between the same two programs on the
+   same two computers over the same network, but this time a direct
+   socket-to-socket connection bypassing the HP-UX Telnet server and pty
+   driver (tell HP-UX C-Kermit to "set host /server * 3000 /raw"; tell
+   desktop client program to "set host blah 3000 /raw"), everything works
+   perfectly with the default Kermit settings (streaming, 4K packets,
+   liberal control-character unprefixing, 8-bit transparency, etc):
+
+                   Text........    Binary......
+  Stream  Pktlen   GET     SEND    GET     SEND
+    On     4000    OK      OK      OK      OK
+
+   And in this case, transfer rates were approximately 900,000 cps. To
+   verify that the behavior reported here is not caused by the new Kermit
+   release, the same experiment was performed on a Telnet connection from
+   the same PC over the same network to the old 715/33 running HP-UX
+   10.20 and C-Kermit 8.00. Text and binary uploads and downloads worked
+   perfectly (albeit slowly) with all the default settings -- streaming,
+   4K packets, etc.
+    ________________________________________________________________________
+
+  3.2.3. Dialing Out and UUCP Lockfiles in HP-UX
+
+   [ [211]Top ] [ [212]Contents ] [ [213]Section Contents ] [ [214]Next ]
+   [ [215]Previous ]
+
+   HP workstations do not come with dialout devices configured; you have
+   to do it yourself (as root). First look in /dev to see what's there;
+   for example in HP-UX 10.00 or later:
+
+  ls -l /dev/cua*
+  ls -l /dev/tty*
+
+   If you find a tty0p0 device but no cua0p0, you'll need to creat one if
+   you want to dial out; the tty0p0 does not work for dialing out. It's
+   easy: start SAM; in the main Sam window, double-click on Peripheral
+   Device, then in the Peripheral Devices window, double-click on
+   Terminals and Modems. In the Terminals and Modems dialog, click on
+   Actions, then choose "Add modem" and fill in the blanks. For example:
+   Port number 0, speed 57600 (higher speeds tend not to work reliably),
+   "Use device for calling out", do NOT "Receive incoming calls" (unless
+   you know what you are doing), leave "CCITT modem" unchecked unless you
+   really have one, and do select "Use hardware flow control (RTS/CTS)".
+   Then click OK. This creates cua0p0 as well as cul0p0 and ttyd0p0
+
+   If the following sequence:
+
+  set line /dev/cua0p0 ; or other device
+  set speed 115200     ; or other normal speed
+
+   produces the message "?Unsupported line speed". This means either that
+   the port is not configured for dialout (go into SAM as described above
+   and make sure "Use device for calling out" is selected), or else that
+   speed you have given (such as 460800) is supported by the operating
+   system but not by the physical device (in which case, use a lower
+   speed like 57600).
+
+   In HP-UX 9.0, serial device names began to change. The older names
+   looked like "/dev/cua00", "/dev/tty01", etc (sometimes with only one
+   digit). The newer names have two digits with the letter "p" in
+   between. HP-UX 8.xx and earlier have the older form, HP-UX 10.00 and
+   later have the newer form. HP-UX 9.xx has the newer form on Series 800
+   machines, and the older form on other hardware models. The situation
+   is summarized in the following table (the Convio 10.0 column applies
+   to HP-UX 10 and 11).
+
+  Converged HP-UX Serial I/O Filenames : TTY Mux Naming
+  ---------------------------------------------------------------------
+  General meaning      Old Form     S800 9.0           Convio 10.0
+  ---------------------------------------------------------------------
+  tty* hardwired ports  tty<YY>     tty<X>p<Y>         tty<D>p<p>
+                                    diag:mux<X>        diag:mux<D>
+  ---------------------------------------------------------------------
+  ttyd* dial-in modems  ttyd<YY>    ttyd<X>p<Y>        ttyd<D>p<p>
+                                    diag:ttyd<X>p<Y>   diag:ttyd<D>p<p>
+  ---------------------------------------------------------------------
+  cua* auto-dial out    cua<YY>     cua<X>p<Y>         cua<D>p<p>
+                                    diag:cua<X>p<Y>
+  ---------------------------------------------------------------------
+  cul* dial-out         cul<YY>     cul<X>p<Y>         cul<D>p<p>
+                                    diag:cul<X>p<Y>
+  ---------------------------------------------------------------------
+   <X>= LU (Logical Unit)  <D>= Devspec (decimal card instance)
+   <Y> or <YY> = Port      <p>= Port
+
+   For dialing out, you should use the cua or cul devices. When
+   C-Kermit's CARRIER setting is AUTO or ON, C-Kermit should pop back to
+   its prompt automatically if the carrier signal drops, e.g. when you
+   log out from the remote computer or service. If you use the tty<D>p<d>
+   (e.g. tty0p0) device, the carrier signal should be ignored. The
+   tty<D>p<d> device should be used for direct connections where the
+   carrier signal does not follow RS-232 conventions (use the cul device
+   for hardwired connections through a true null modem). Do not use the
+   ttyd<D>p<d> device for dialing out.
+
+   Kermit's access to serial devices is controlled by "UUCP lockfiles",
+   which are intended to prevent different users using different software
+   programs (Kermit, cu, etc, and UUCP itself) from accessing the same
+   serial device at the same time. When a device is in use by a
+   particular user, a file with a special name is created in:
+
+  /var/spool/locks  (HP-UX 10.00 and later)
+  /usr/spool/uucp   (HP-UX 9.xx and earlier)
+
+   The file's name indicates the device that is in use, and its contents
+   indicates the process ID (pid) of the process that is using the
+   device. Since serial devices and the locks directory are not both
+   publicly readable and writable, Kermit and other communication
+   software must be installed setuid to the owner (bin) of the serial
+   device and setgid to the group (daemon) of the /var/spool/locks
+   directory. Kermit's setuid and setgid privileges are enabled only when
+   opening the device and accessing the lockfiles.
+
+   Let's say "unit" means a string of decimal digits (the interface
+   instance number) followed (in HP-UX 10.00 and later) by the letter "p"
+   (lowercase), followed by another string of decimal digits (the port
+   number on the interface), e.g.:
+
+  "0p0", "0p1", "1p0", etc       (HP-UX 10.00 and later)
+  "0p0", "0p1", "1p0", etc       (HP-UX 9.xx on Series 800)
+  "00",  "01",  "10",  "0", etc  (HP-UX 9.xx not on Series 800)
+  "00",  "01",  "10",  "0", etc  (HP-UX 8.xx and earlier)
+
+   Then a normal serial device (driver) name consists of a prefix ("tty",
+   "ttyd", "cua", "cul", or possibly "cuad" or "culd") followed by a
+   unit, e.g. "cua0p0". Kermit's treatment of UUCP lockfiles is as close
+   as possible to that of the HP-UX "cu" program. Here is a table of the
+   lockfiles that Kermit creates for unit 0p0:
+
+  Selection      Lockfile 1     Lockfile 2  
+  /dev/tty0p0    LCK..tty0p0    (none)
+* /dev/ttyd0p0   LCK..ttyd0p0   (none)
+  /dev/cua0p0    LCK..cua0p0    LCK..ttyd0p0
+  /dev/cul0p0    LCK..cul0p0    LCK..ttyd0p0
+  /dev/cuad0p0   LCK..cuad0p0   LCK..ttyd0p0
+  /dev/culd0p0   LCK..culd0p0   LCK..ttyd0p0
+  <other>        LCK..<other>   (none)
+
+   (* = Dialin device, should not be used.)
+
+   In other words, if the device name begins with "cu", a second lockfile
+   for the "ttyd" device, same unit, is created, which should prevent
+   dialin access on that device.
+
+   The <other> case allows for symbolic links, etc, but of course it is
+   not foolproof since we have no way of telling which device is really
+   being used.
+
+   When C-Kermit tries to open a dialout device whose name ends with a
+   "unit", it searches the lockfile directory for all possible names for
+   the same unit. For example, if user selects /dev/cul2p3, Kermit looks
+   for lockfiles named:
+
+  LCK..tty2p3
+  LCK..ttyd2p3
+  LCK..cua2p3
+  LCK..cul2p3
+  LCK..cuad2p3
+  LCK..culd2p3
+
+   If any of these files are found, Kermit opens them to find out the ID
+   (pid) of the process that created them; if the pid is still valid, the
+   process is still active, and so the SET LINE command fails and the
+   user is informed of the pid so s/he can use "ps" to find out who is
+   using the device.
+
+   If the pid is not valid, the file is deleted. If all such files (i.e.
+   with same "unit" designation) are successfully removed, then the SET
+   LINE command succeeds; up to six messages are printed telling the user
+   which "stale lockfiles" are being removed.
+
+   When the "set line" command succeeds in HP-UX 10.00 and later,
+   C-Kermit also creates a Unix System V R4 "advisory lock" as a further
+   precaution (but not guarantee) against any other process obtaining
+   access to the device while you are using it.
+
+   If the selected device was in use by "cu", Kermit can't open it,
+   because "cu" has changed its ownership, so we never get as far as
+   looking at the lockfiles. In the normal case, we can't even look at
+   the device to see who the owner is because it is visible only to its
+   (present) owner. In this case, Kermit says (for example):
+
+  /dev/cua0p0: Permission denied
+
+   When Kermit releases a device it has successfully opened, it removes
+   all the lockfiles that it created. This also happens whenever Kermit
+   exits "under its own power".
+
+   If Kermit is killed with a device open, the lockfile(s) are left
+   behind. The next Kermit program that tries to assign the device, under
+   any of its various names, will automatically clean up the stale
+   lockfiles because the pids they contain are invalid. The behavior of
+   cu and other communication programs under these conditions should be
+   the same.
+
+   Here, by the way, is a summary of the differences between the HP-UX
+   port driver types from John Pezzano of HP:
+
+     There are three types of device files for each port.
+
+     The ttydXXX device file is designed to work as follows:
+
+    1. The process that opens it does NOT get control of the port until
+       CD is asserted. This was intentional (over 15 years ago) to allow
+       getty to open the port but not control it until someone called in.
+       If a process wants to use the direct or callout device files
+       (ttyXXX and culXXX respectively), they will then get control and
+       getty would be blocked. This eliminated the need to use uugetty
+       (and its inherent problems with lock files) for modems. You can
+       see this demonstrated by the fact that "ps -ef" shows a ? in the
+       tty column for the getty process as getty does not have the port
+       yet.
+    2. Once CD is asserted, the port is controlled by getty (or the
+       process handling an incoming call) if there was no process using
+       the port. The ? in the "ps" command now shows the port. At this
+       point, the port accepts data.
+
+     Therefore you should use either the callout culXXX device file
+     (immediate control but no data until CD is asserted) or the direct
+     device file ttyXXX which gives immediate control and immediate data
+     and which ignores by default modem control signals.
+
+     The ttydXXX device should be used only for callin and my
+     recommendation is to use it only for getty and uugetty.
+    ________________________________________________________________________
+
+  3.2.4 Notes on Specific HP-UX Releases
+
+   SECTION CONTENTS
+
+  3.2.4.1. [216]HP-UX 11
+  3.2.4.2. [217]HP-UX 10
+  3.2.4.3. [218]HP-UX 9
+  3.2.4.4. [219]HP-UX 8
+  3.2.4.5. [220]HP-UX 7 and Earlier
+
+  3.2.4.1. HP-UX 11
+
+   [ [221]Top ] [ [222]Contents ] [ [223]Section Contents ] [ [224]Next ]
+
+   As noted in [225]Section 3.2.2, the HP-UX 11 Telnet server and/or
+   pseudoterminal driver are a serious impediment to file transfer over
+   Telnet connections into HP-UX. If you have a Telnet connection into
+   HP-UX 11, tell your desktop Kermit program to:
+
+  set streaming off
+  set receive packet-length 2000
+  set send packet-length 500
+
+   File transfer speeds over connections from HP-UX 11 (dialed or Telnet)
+   are not impeded whatsoever, and can go at whatever speed is allowed by
+   the connection and the Kermit partner on the far end.
+
+   PA-RISC binaries for HP-UX 10.20 or later should run on any PA-RISC
+   system, S700 or S800, as long as the binary was not built under a
+   later HP-UX version than the host operating system. HP-UX 11.00 and
+   11.11 are only for PA-RISC systems. HP-UX 11.20 is only for IA64
+   (subsequent HP-UX releases will be for both PA-RISC and IA64). To
+   check binary compatibility, the following C-Kermit 8.0 binaries were
+   run successfully on an HP-9000/785 with HP-UX 11.11:
+
+     * Model 7xx HP-UX 10.20
+     * Model 8xx HP-UX 10.20
+     * Model 7xx HP-UX 11.00
+     * Model 8xx HP-UX 11.00
+     * Model 7xx HP-UX 11.11
+     * Model 8xx HP-UX 11.11
+
+   Binaries built under some of the earlier HP-UX releases, such as 9.05,
+   might also work, but only if built for the same hardware family (e.g.
+   s700).
+    ________________________________________________________________________
+
+  3.2.4.2. HP-UX 10
+
+   [ [226]Top ] [ [227]Contents ] [ [228]Section Contents ] [ [229]Next ]
+   [ [230]Previous ]
+
+   Beginning in HP-UX 10.10, libcurses is linked to libxcurses, the new
+   UNIX95 (X/Open) version of curses, which has some serious bugs; some
+   routines, when called, would hang and never return, some would dump
+   core. Evidently libxcurses contains a select() routine, and whenever
+   C-Kermit calls what it thinks is the regular (sockets) select(), it
+   gets the curses one, causing a segmentation fault. There is a patch
+   for this from HP, PHCO_8086, "s700_800 10.10 libcurses patch", "shared
+   lib curses program hangs on 10.10", "10.10 enhanced X/Open curses core
+   dumps due to using wrong select call", 96/08/02 (you can tell if the
+   patch is installed with "what /usr/lib/libxcurses.1"; the unpatched
+   version is 76.20, the patched one is 76.20.1.2). It has been verified
+   that C-Kermit works OK with the patched library, but results are not
+   definite for HP-UX 10.20 or higher.
+
+   To ensure that C-Kermit works even on non-patched HP-UX 10.10 systems,
+   separate makefile entries are provided for HP-UX 10.00/10.01, 10.10,
+   10.20, etc, in which the entries for 10.10 and above link with
+   libHcurses, which is "HP curses", the one that was used in
+   10.00/10.01. HP-UX 11.20 and later, however, link with libcurses, as
+   libHcurses disappeared in 11.20.
+    ________________________________________________________________________
+
+  3.2.4.3. HP-UX 9
+
+   [ [231]Top ] [ [232]Contents ] [ [233]Section Contents ] [ [234]Next ]
+   [ [235]Previous ]
+
+   HP-UX 9.00 and 9.01 need patch PHNE_10572 (note: this replaces
+   PHNE_3641) for hptt0.o, asio0.o, and ttycomn.o in libhp-ux.a. Contact
+   Hewlett Packard if you need this patch. Without it, the dialout device
+   (tty) will be hung after first use; subsequent attempts to use will
+   return an error like "device busy". (There are also equivalent patches
+   for s700 9.03 9.05 9.07 (PHNE_10573) and s800 9.00 9.04 (PHNE_10416).
+
+   When C-Kermit is in server mode, it might have trouble executing
+   REMOTE HOST commands. This problem happens under HP-UX 9.00 (Motorola)
+   and HP-UX 9.01 (RISC) IF the C-Shell is the login shell AND with the
+   C-Shell Revision 70.15. Best thing is to install HP's Patch PHCO_4919
+   for Series 300/400 and PHCO_5015 for the Series 700/800. PHCO_5015 is
+   called "s700_800 9.X cumulative csh(1) patch with memory leak fix"
+   which works for HP-UX 9.00, 9.01, 9.03, 9.04, 9.05 and 9.07. At least
+   you need C-Shell Revision 72.12!
+
+   C-Kermit works fine -- including its curses-based file-transfer
+   display -- on the console terminal, in a remote session (e.g. when
+   logged in to the HP 9000 on a terminal port or when telnetted or
+   rlogin'd), and in an HP-VUE hpterm window or an xterm window.
+    ________________________________________________________________________
+
+  3.2.4.4. HP-UX 8
+
+   [ [236]Top ] [ [237]Contents ] [ [238]Section Contents ] [ [239]Next ]
+   [ [240]Previous ]
+
+   To make C-Kermit work on HP-UX 8.05 on a model 720, obtain and install
+   HP-UX patch PHNE_0899. This patch deals with a lot of driver issues,
+   particularly related to communication at higher speeds.
+
+   One user reports:
+
+     On HP-UX 8 DON'T install 'tty patch' PHKL_4656, install PHKL_3047
+     instead! Yesterday I tried this latest tty patch PHKL_4656 and had
+     terrible problems. This patch should fix RTS/CTS problems. With
+     text transver all looks nice. But when I switched over to binary
+     files the serial interface returned only rubish to C-Kermit. All
+     sorts of protocol, CRC and packed errors I had. After several tests
+     and after uninstalling that patch, all transvers worked fine. MB's
+     of data without any errors. So keep your fingers away from that
+     patch. If anybody needs the PHKL_3047 patch I have it here. It is
+     no longer availabel from HP's patch base.
+    ________________________________________________________________________
+
+  3.2.4.5. HP-UX 7 and Earlier
+
+   [ [241]Top ] [ [242]Contents ] [ [243]Section Contents ] [
+   [244]Previous ]
+
+   When transferring files into HP-UX 5 or 6 over a Telnet connection,
+   you must not use streaming, and you must not use a packet length
+   greater than 512. However, you can use streaming and longer packets
+   when sending files from HP-UX on a Telnet connection. In C-Kermit 8.0,
+   the default receive packet length for HP-UX 5 and 6 was changed to 500
+   (but you can still increase it with SET RECEIVE PACKET-LENGTH if you
+   wish, e.g. for non-Telnet connections). Disable streaming with SET
+   STREAMING OFF.
+
+   The HP-UX 5.00 version of C-Kermit does not include the fullscreen
+   file-transfer because of problems with the curses library.
+
+   If HP-UX 5.21 with Wollongong TCP/IP is on the remote end of a Telnet
+   connection, streaming transfers to HP-UX invariably fail. Workaround:
+   SET STREAMING OFF. Packets longer than about 1000 should not be used.
+   Transfers from these systems, however, can use streaming and/or longer
+   packets.
+
+   Reportedly, "[there is] a bug in C-Kermit using HP-UX version 5.21 on
+   the HP-9000 series 500 computers. It only occurs when the controlling
+   terminal is using an HP-27140 six-port modem mux. The problem is not
+   present if the controlling terminal is logged into an HP-27130
+   eight-port mux. The symptom is that just after dialing successfully
+   and connecting Kermit locks up and the port is unusable until both
+   forks of Kermit and the login shell are killed." (This report predates
+   C-Kermit 6.0 and might no longer apply.)
+    ________________________________________________________________________
+
+  3.2.5. HP-UX and X.25
+
+   [ [245]Top ] [ [246]Contents ] [ [247]Section Contents ] [
+   [248]Previous ]
+
+   Although C-Kermit presently does not include built-in support for
+   HP-UX X.25 (as it does for the Sun and IBM X.25 products), it can
+   still be used to make X.25 connections as follows: start Kermit and
+   then telnet to localhost. After logging back in, start padem as you
+   would normally do to connect over X.25. Padem acts as a pipe between
+   Kermit and X.25. In C-Kermit 7.0, you might also be able to avoid the
+   "telnet localhost" step by using:
+
+  C-Kermit> pty padem address
+
+   This works if padem uses standard i/o (who knows?).
+    ________________________________________________________________________
+
+  3.3. C-KERMIT AND LINUX
+
+   [ [249]Top ] [ [250]Contents ] [ [251]Section Contents ] [ [252]Next ]
+   [ [253]Previous ]
+
+   SECTION CONTENTS
+
+  3.3.1. [254]Problems Building C-Kermit for Linux
+  3.3.2. [255]Problems with Serial Devices in Linux
+  3.3.3. [256]Terminal Emulation in Linux
+  3.3.4. [257]Dates and Times
+  3.3.5. [258]Startup Errors
+  3.3.6. [259]The Fullscreen File Transfer Display
+
+   REFERENCES
+
+   For further information, read the [260]comp.os.linux.misc,
+   [261]comp.os.linux.answers, and other Linux-oriented newsgroups, and
+   see:
+
+   The Linux Document Project (LDP)
+          [262]http://www.tldp.org/
+
+   The Linux FAQ
+          [263]http://www.tldp.org/FAQ/Linux-FAQ.html
+
+   The Linux HOWTOs (especially the Serial HOWTO)
+
+     [264]http://www.tldp.org/HOWTO/Serial-HOWTO.html
+
+     [265]http://tldp.org/HOWTO/Modem-HOWTO.html
+
+     [266]ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO
+
+     [267]ftp://tsx-11.mit.edu/pub/linux/docs/HOWTO
+
+     [268]http://www.tldp.org/HOWTO/
+
+     [269]http://www.tldp.org/hmirrors.html
+
+   Linux Vendor Tech Support Pages:
+
+     [270]http://www.redhat.com/apps/support/
+
+     [271]http://www.debian.org/support
+
+     [272]http://www.slackware.com/support/
+
+     [273]http://www.caldera.com/support/
+
+     [274]http://www.suse.com/support/
+
+     [275]http://www.mandrake.com/support/
+
+     [276]http://www.turbolinux.com/support/
+
+   Linux Winmodem Support
+          [277]http://www.linmodems.org/
+
+   Also see general comments on PC-based Unixes in [278]Section 3.0.
+
+   What Linux version is it? -- "uname -a" supplies only kernel
+   information, but these days it's the distribution that matters: Red
+   Hat 7.3, Debian 2.2, Slackware 8.0, etc. Unfortunately there's no
+   consistent way to get the distribution version. Usually it's in a
+   distribution-specific file:
+
+     Red Hat:   /etc/issue or /etc/redhat-release
+     Debian:    /etc/debian_version
+     Slackware: /etc/slackware-version (at least in later versions)
+
+   Did you know: DECnet is available for Linux? See:
+
+  [279]http://linux.dreamtime.org/decnet/
+
+   (But there is no support for it in C-Kermit -- anybody interested in
+   adding it, please [280]let us know).
+
+   Before proceeding, let's handle the some of the most frequently asked
+   question in the Linux newsgroups:
+
+    1. Neither C-Kermit nor any other Linux application can use
+       Winmodems, except in the [281]rare cases where Linux drivers have
+       been written for them. See [282]Section 3.0.2 for details.
+    2. "Why does it take such a long time to make a telnet connection to
+       (or from) my Linux PC?" (this applies to C-Kermit and to regular
+       Telnet). Most telnet servers these days perform reverse DNS
+       lookups on the client (for security and/or logging reasons). If
+       the Telnet client's address cannot be found by the server's local
+       DNS server, the DNS request goes out to the Internet at large, and
+       this can take quite some time. The solution to this problem is to
+       make sure that both client and host are registered in DNS, and
+       that the registrations are exported. C-Kermit itself performs
+       reverse DNS lookups unless you tell it not to; this is to allow
+       C-Kermit to let you know which host it is actually connected to in
+       case you have made a connection to a host pool (multihomed host).
+       You can disable C-Kermit's reverse DNS lookup with SET TCP
+       REVERSE-DNS-LOOKUP OFF.
+    3. (Any question that has the word "Telnet" in it...) The knee-jerk
+       reaction is "don't use Telnet, use SSH!" There's nothing wrong
+       with Telnet. In fact it's far superior to SSH as a protocol in
+       terms of features and extensibility, not to mention platform
+       neutrality. The issue lurking behind the knee-jerk reaction is
+       security. SSH is thought to be secure, whereas Telnet is thought
+       to be insecure. This is true for clear-text Telnet (because
+       passwords travel in the clear across the network), but apparently
+       few people realize that [283]secure Telnet clients and servers
+       have been available for years, and these are more secure than SSH
+       (for reasons explained [284]HERE.
+    4. (Any question that has the word "FTP" in it...) The knee-jerk
+       reaction being "Don't use FTP, use SCP!" (or SFTP). Same answer as
+       above, but moreso. SCP and SFTP are not only not platform neutral,
+       they're diversity-hostile. They transfer files only in binary
+       mode, which mangles text files across different platforms, to the
+       same degree the platform's text-file record format and character
+       set differ. An extreme example would be an Variable-Block format
+       EBCDIC text file on an IBM mainframe, binary transfer of which to
+       Unix would do you little good indeed. FTP was designed with
+       diversity in mind and secure versions are available.
+    ________________________________________________________________________
+
+  3.3.1. Problems Building C-Kermit for Linux
+
+   [ [285]Top ] [ [286]Contents ] [ [287]Section Contents ] [ [288]Next ]
+
+   Modern Linux distributions like Red Hat give you a choice at
+   installation whether to include "developer tools". Obviously, you
+   can't build C-Kermit or any other C program from source code if you
+   have not installed the developer tools. But to confuse matters, you
+   might also have to choose (separately) to install the "curses" or
+   "ncurses" terminal control library; thus it is possible to install the
+   C compiler and linker, but omit the (n)curses library and headers. If
+   curses is not installed, you will not be able to build a version of
+   C-Kermit that supports the fullscreen file-transfer display, in which
+   case you'll need to use the "linuxnc" makefile target (nc = No Curses)
+   or else install ncurses before building.
+
+   There are all sorts of confusing issues caused by the many and varied
+   Linux distributions. Some of the worst involve the curses library and
+   header files: where are they, what are they called, which ones are
+   they really? Other vexing questions involve libc5 vs libc6 vs glibc vs
+   glibc2 (C libraries), gcc vs egcs vs lcc (compilers), plus using or
+   avoiding features that were added in a certain version of Linux or a
+   library or a distribution, and are not available in others. As of
+   C-Kermit 8.0, these questions should be resolved by the "linux"
+   makefile target itself, which does a bit of looking around to see
+   what's what, and then sets the appropriate CFLAGS.
+    ________________________________________________________________________
+
+  3.3.2. Problems with Serial Devices in Linux
+
+   [ [289]Top ] [ [290]Contents ] [ [291]Section Contents ] [ [292]Next ]
+   [ [293]Previous ]
+
+     Also see: "man setserial", "man irqtune".
+     And: [294]Sections 3.0, [295]6, [296]7, and [297]8 of this
+     document.
+
+     NOTE: Red Hat Linux 7.2 and later include a new API that allows
+     serial-port arbitration by non-setuid/gid programs. This API has
+     not yet been added to C-Kermit. If C-Kermit is to be used for
+     dialing out on Red Hat 7.2 or later, it must still be installed as
+     described in in Sections [298]10 and [299]11 of the
+     [300]Installation Instructions. 
+
+   Don't expect it to be easy. Queries like the following are posted to
+   the Linux newsgroups almost daily:
+
+     Problem of a major kind with my Compaq Presario 1805 in the sense
+     that the pnpdump doesn't find the modem and the configuration tells
+     me that the modem is busy when I set everything by hand!
+
+     I have <some recent SuSE distribution>, kernel 2.0.35. Using the
+     Compaq tells me that the modem (which is internal) is on COM2, with
+     the usual IRQ and port numbers. Running various Windows diagnostics
+     show me AT-style commands exchanged so I have no reason to beleive
+     that it is a Winmodem. Also, the diagnostics under Win98 tell me
+     that I am talking to an NS 16550AN.
+
+   [Editor's note: This does not necessarily mean it isn't a Winmodem.]
+
+     Under Linux, no joy trying to talk to the modem on /dev/cua1
+     whether via minicom, kppp, or chat; kppp at least tells me that
+     tcgetattr() failed.
+
+     Usage of setserial:
+
+  setserial /dev/cua1 port 0x2F8 irq 3 autoconfig
+  setserial -g /dev/cua1
+
+     tells me that the uart is 'unknown'. I have tried setting the UART
+     manullay via. setserial to 16550A, 16550, and the other one (8550?)
+     (I didn't try 16540). None of these manual settings resulted in any
+     success.
+
+     A look at past articles leads me to investigate PNP issues by
+     calling pnpdump but pnpdump returns "no boards found". I have
+     looked around on my BIOS (Phoenix) and there is not much evidence
+     of it being PNP aware. However for what it calls "Serial port A",
+     it offers a choice of Auto, Disabled or Manual settings (currently
+     set to Auto), but using the BIOS interface I tried to change to
+     'manual' and saw the default settings offered to be were 0x3F8 and
+     IRQ 4 (COM1). The BIOS menus did not give me any chance to
+     configure COM2 or any "modem". I ended up not saving any BIOS
+     changes in the course of my investigations.
+
+   You can also find out a fair amount about your PC's hardware
+   configuration in the text files in /proc, e.g.:
+
+  -r--r--r--    1 root            0 Sep  4 14:00 /proc/devices
+  -r--r--r--    1 root            0 Sep  4 14:00 /proc/interrupts
+  -r--r--r--    1 root            0 Sep  4 14:00 /proc/ioports
+  -r--r--r--    1 root            0 Sep  4 14:00 /proc/pci
+
+   From the directory listing they look like empty files, but in fact
+   they are text files that you "cat":
+
+$ cat /proc/pci
+   Bus  0, device  14, function  0:
+     Serial controller: US Robotics/3Com 56K FaxModem Model 5610 (rev 1).
+       IRQ 10.
+       I/O at 0x1050 [0x1057].
+
+$ setserial -g /dev/ttyS4
+/dev/ttyS4, UART: 16550A, Port: 0x1050, IRQ: 10
+
+$ cat /proc/ioports
+1050-1057 : US Robotics/3Com 56K FaxModem Model 5610
+   1050-1057 : serial(auto)
+
+$ cat /proc/interrupts
+            CPU0
+   0:    7037515          XT-PIC  timer
+   1:          2          XT-PIC  keyboard
+   2:          0          XT-PIC  cascade
+   4:          0          XT-PIC  serial
+   8:          1          XT-PIC  rtc
+   9:     209811          XT-PIC  usb-uhci, eth0
+  14:     282015          XT-PIC  ide0
+  15:          6          XT-PIC  ide1
+
+   Watch out for PCI, PCMCIA and Plug-n-Play devices, Winmodems, and the
+   like (see cautions in [301]Section 3.0 Linux supports Plug-n-Play
+   devices to some degree via the isapnp and pnpdump programs; read the
+   man pages for them. (If you don't have them, look on your installation
+   CD for isapnptool or download it from sunsite or a sunsite mirror or
+   other politically correct location du jour).
+
+   PCI modems do not use standard COM port addresses. The I/O address and
+   IRQ are assigned by the BIOS. All you need to do to get one working,
+   find out the I/O address and interrupt number with (as root) "lspci -v
+   | more" and then give the resulting address and interrupt number to
+   setserial.
+
+   Even when you have a real serial port, always be wary of interrupt
+   conflicts and similar PC hardware configuration issues: a PC is not a
+   real computer like other Unix workstations -- it is generally pieced
+   together from whatever random components were the best bargain on the
+   commodity market the week it was built. Once it's assembled and boxed,
+   not even the manufacturer will remember what it's made of or how it
+   was put together because they've moved on to a new model. Their job is
+   to get it (barely) working with Windows; for Linux and other OS's you
+   are on your own.
+
+   "set line /dev/modem" or "set line /dev/ttyS2", etc, results in an
+   error, "/dev/modem is not a tty". Cause unknown, but obviously a
+   driver issue, not a Kermit one (Kermit uses "isatty()" to check that
+   the device is a tty, so it knows it will be able to issue all the
+   tty-related ioctl's on it, like setting the speed & flow control). Try
+   a different name (i.e. driver) for the same port, e.g. "set line
+   /dev/cua2" or whatever.
+
+   To find what serial ports were registered at the most recent system
+   boot, type (as root): "grep tty /var/log/dmesg".
+
+   "set modem type xxx" (where xxx is the name of a modem) followed by
+   "set line /dev/modem" or "set
+   line /dev/ttyS2", etc, hangs (but can be interrupted with Ctrl-C).
+   Experimentation shows that if the modem is configured to always assert
+   carrier (&C0) the same command does not hang. Again, a driver issue.
+   Use /dev/cua2 (or whatever) instead. (Or not -- hopefully none of
+   these symptoms occurs in C-Kermit 7.0 or later.)
+
+   "set line /dev/cua0" reports "Device is busy", but "set line
+   /dev/ttyS0" works OK.
+
+   In short: If the cua device doesn't work, try the corresponding ttyS
+   device. If the ttyS device doesn't work, try the corresponding cua
+   device -- but note that Linux developers do not recommend this, and
+   are phasing out the cua devices. From /usr/doc/faq/howto/Serial-HOWTO:
+
+   12.4. What's The Real Difference Between the /dev/cuaN And /dev/ttySN
+          Devices?
+          The only difference is the way that the devices are opened. The
+          dialin devices /dev/ttySN are opened in blocking mode, until CD
+          is asserted (ie someone connects). So, when someone wants to
+          use the /dev/cuaN device, there is no conflict with a program
+          watching the /dev/ttySN device (unless someone is connected of
+          course). The multiple /dev entries, allow operation of the same
+          physical device with different operating characteristics. It
+          also allows standard getty programs to coexist with any other
+          serial program, without the getty being retrofitted with
+          locking of some sort. It's especially useful since standard
+          Unix kernel file locking, and UUCP locking are both advisory
+          and not mandatory.
+
+   It was discovered during development of C-Kermit 7.0 that rebuilding
+   C-Kermit with -DNOCOTFMC (No Close/Open To Force Mode Change) made the
+   aforementioned problem with /dev/ttyS0 go away. It is not yet clear,
+   however, what its affect might be on the /dev/cua* devices. As of 19
+   March 1998, this option has been added to the CFLAGS in the makefile
+   entries for Linux ("make linux").
+
+   Note that the cua device is now "deprecated", and new editions of
+   Linux will phase (have phased) it out in favor of the ttyS device. See
+   (if it's still there):
+
+  [302]http://linuxwww.db.erau.edu/mail_archives/linux-kernel/Mar_98/1441.html
+
+   (no, of course it isn't; you'll have to use your imagination). One
+   user reported that C-Kermit 7.0, when built with egcs 1.1.2 and run on
+   Linux 2.2.6 with glibc 2.1 (hardware unknown but probably a PC) dumps
+   core when given a "set line /dev/ttyS1" command. When rebuilt with
+   gcc, it works fine.
+
+   All versions of Linux seem to have the following deficiency: When a
+   modem call is hung up and CD drops, Kermit can no longer read the
+   modem signals; SHOW COMMUNICATIONS says "Modem signals not available".
+   The TIOCMGET ioctl() returns -1 with errno 5 ("I/O Error").
+
+   The Linux version of POSIX tcsendbreak(), which is used by C-Kermit to
+   send regular (275msec) and long (1.5sec) BREAK signals, appears to
+   ignore its argument (despite its description in the man page and info
+   topic), and always sends a regular 275msec BREAK. This has been
+   observed in Linux versions ranging from Debian 2.1 to Red Hat 7.1.
+    ________________________________________________________________________
+
+  3.3.3. Terminal Emulation in Linux
+
+   [ [303]Top ] [ [304]Contents ] [ [305]Section Contents ] [ [306]Next ]
+   [ [307]Previous ]
+
+   C-Kermit is not a terminal emulator. For a brief explanation of why
+   not, see [308]Section 3.0.5. For a fuller explanation, [309]ClICK
+   HERE.
+
+   In Unix, terminal emulation is supplied by the Window in which you run
+   Kermit: the regular console screen, which provides Linux Console
+   "emulation" via the "console" termcap entry, or under X-Windows in an
+   xterm window, which gives VTxxx emulation. An xterm that includes
+   color ANSI and VT220 emulation is available with Xfree86:
+
+  [310]http://dickey.his.com/xterm/xterm.html
+
+   Before starting C-Kermit in an xterm window, you might need to tell
+   the xterm window's shell to "stty sane".
+
+   To set up your PC console keyboard to send VT220 key sequences when
+   using C-Kermit as your communications program in an X terminal window
+   (if it doesn't already), create a file somewhere (e.g. in /root/)
+   called .xmodmaprc, containing something like the following:
+
+  keycode 77  = KP_F1       ! Num Lock     => DEC Gold (PF1)
+  keycode 112 = KP_F2       ! Keypad /     => DEC PF1
+  keycode 63  = KP_F3       ! Keypad *     => DEC PF3
+  keycode 82  = KP_F4       ! Keypad -     => DEC PF4
+  keycode 111 = Help        ! Print Screen => DEC Help
+  keycode 78  = F16         ! Scroll Lock  => DEC Do
+  keycode 110 = F16         ! Pause        => DEC Do
+  keycode 106 = Find        ! Insert       => DEC Find
+  keycode 97  = Insert      ! Home         => DEC Insert
+  keycode 99  = 0x1000ff00  ! Page Up      => DEC Remove
+  keycode 107 = Select      ! Delete       => DEC Select
+  keycode 103 = Page_Up     ! End          => DEC Prev Screen
+  keycode 22  = Delete      ! Backspace sends Delete (127)
+
+   Then put "xmodmap filename" in your .xinitrc file (in your login
+   directory), e.g.
+
+  xmodmap /root/.xmodmaprc
+
+   Of course you can move things around. Use the xev program to find out
+   key codes.
+
+   Console-mode keys are mapped separately using loadkeys, and different
+   keycodes are used. Find out what they are with showkey.
+
+   For a much more complete VT220/320 key mapping for [311]Xfree86 xterm,
+   [312]CLICK HERE.
+    ________________________________________________________________________
+
+  3.3.4. Dates and Times
+
+   [ [313]Top ] [ [314]Contents ] [ [315]Section Contents ] [ [316]Next ]
+   [ [317]Previous ]
+
+   If C-Kermit's date-time (e.g. as shown by its DATE command) differs
+   from the system's date and time:
+
+    a. Make sure the libc to which Kermit is linked is set to GMT or is
+       not set to any time zone. Watch out for mixed libc5/libc6 systems;
+       each must be set indpendently.
+    b. If you have changed your TZ environment variable, make sure it is
+       exported. This is normally done in /etc/profile or /etc/TZ.
+    ________________________________________________________________________
+
+  3.3.5. Startup Errors
+
+   [ [318]Top ] [ [319]Contents ] [ [320]Section Contents ] [ [321]Next ]
+   [ [322]Previous ]
+
+   C-Kermit should work on all versions of Linux current through March
+   2003, provided it was built on the same version you have, with the
+   same libraries and header files (just get the source code and "make
+   linux"). Binaries tend not to travel well from one Linux machine to
+   another, due to their many differences. There is no guarantee that a
+   particular C-Kermit binary will not stop working at a later date,
+   since Linux tends to change out from under its applications. If that
+   happens, rebuild C-Kermit from source. If something goes wrong with
+   the build process, look on the [323]C-Kermit website for a newer
+   version. If you have the latest version, then [324]report the problem
+   to us.
+
+   Inability to transfer files in Red Hat 7.2: the typical symptom would
+   be if you start Kermit and tell it to RECEIVE, it fails right away
+   with "?/dev/tty: No such device or address" or "?Bad file descriptor".
+   One report says this is because of csh, and if you change your shell
+   to bash or other shell, it doesn't happen. Another report cite bugs in
+   Red Hat 7.2 Telnetd "very seldom (if ever) providing a controlling
+   tty, and lots of other people piled on saying they have the same
+   problem.") A third theory is that this happens only when Linux has
+   been installed without "virtual terminal support".
+
+   A search of RedHat's errata pages shows a bug advisory (RHBA-2001-153)
+   issued 13 November 2001, but updated 6 December, about this same
+   symptom (but with tcsh and login.) Seems that login was not always
+   assigning a controlling TTY for the session, which would make most use
+   of "/dev/tty" somewhat less than useful.
+
+  [325]http://www.redhat.com/support/errata/RHBA-2001-153.html
+
+   Quoting: "Due to terminal handling problems in /bin/login, tcsh would
+   not find the controlling terminal correctly, and a shell in single
+   user mode would exhibit strange terminal input characteristics. This
+   update fixes both of these problems."
+
+   Since the Red Hat 5.1 release (circa August 1998), there have been
+   numerous reports of prebuilt Linux executables, and particularly the
+   Kermit RPM for Red Hat Linux, not working; either it won't start at
+   all, or it gives error messages about "terminal type unknown" and
+   refuses to initialize its curses support. The following is from the
+   [326]Kermit newsgroup:
+
+     From: rchandra@hal9000.buf.servtech.com
+     Newsgroups: comp.protocols.kermit.misc
+     Subject: Red Hat Linux/Intel 5.1 and ncurses: suggestions
+     Date: 22 Aug 1998 15:54:46 GMT
+     Organization: Verio New York
+     Keywords: RedHat RPM 5.1
+
+     Several factors can influence whether "linux" is recognized as a
+     terminal type on many Linux systems.
+
+    1. Your program, or the libraries it linked with (if statically
+       linked), or the libraries it dynamically links with at runtime,
+       are looking for an entry in /etc/termcap that isn't there. (not
+       likely, but possible... I believe but am not certain that this is
+       a very old practice in very old [n]curses library implementations
+       to use a single file for all terminal descriptions.)
+    2. Your program, or the libraries...are looking for a terminfo file
+       that just plain isn't there. (also not so likely, since many
+       people in other recent message threads said that other programs
+       work OK).
+    3. Your program, or the libraries...are looking for a terminfo file
+       that is stored at a pathname that isn't expected by your program,
+       the libraries--and so on. I forgot if I read this in the errata
+       Web page or where exactly I discovered this (Netscape install?
+       Acrobat install?), but it may just be that one libc (let's say for
+       sake of argument, libc5, but I don't know this to be true) expects
+       your terminfo to be in /usr/share/terminfo, and the other (let's
+       say libc6/glibc) expects /usr/lib/terminfo. I remember that the
+       specific instructions in this bugfix/workaround were to do the
+       following or equivalent:
+  cd /usr/lib
+  ln -s ../share/terminfo ./terminfo
+       or:
+  ln -s /usr/share/terminfo /usr/lib/terminfo
+
+     So what this says is that the terminfo database/directory structure
+     can be accessed by either path. When something goes to reference
+     /usr/lib/terminfo, the symlink redirects it to essentially
+     /usr/share/terminfo, which is where it really resides on your
+     system. I personally prefer wherever possible to use relative
+     symlinks, because they still hold, more often than break, across
+     mount points, particularly NFS mounts, where the directory
+     structure may be different on the different systems.
+
+   Evidently the terminfo file moved between Red Hat 5.0 and 5.1, but Red
+   Hat did not include a link to let applications built prior to 5.1 find
+   it. Users reported that installing the link fixes the problem.
+    ________________________________________________________________________
+
+  3.3.6. The Fullscreen File Transfer Display
+
+   [ [327]Top ] [ [328]Contents ] [ [329]Section Contents ] [
+   [330]Previous ]
+
+   Starting with ncurses versions dated 1998-12-12 (about a year before
+   ncurses 5.0), ncurses sets the terminal for buffered i/o, but
+   unfortunately is not able to restore it upon exit from curses (via
+   endwin()). Thus after a file transfer that uses the fullscreen file
+   transfer display, the terminal no longer echos nor responds
+   immediately to Tab, ?, and other special command characters. The same
+   thing happens on other platforms that use ncurses, e.g. FreeBSD.
+   Workarounds:
+
+     * Use SET XFER DISPLAY BRIEF, CRT, SERIAL, or NONE instead of
+       FULLSCREEN; or:
+     * Rebuild with KFLAGS=-DNONOSETBUF (C-Kermit 8.0)
+
+   In Red Hat 7.1, when using C-Kermit in a Gnome terminal window, it was
+   noticed that when the fullscreen file transfer display exits (via
+   endwin()), the previous (pre-file-transfer-display) screen is
+   restored. Thus you can't look at the completed display to see what
+   happened. This is a evidently a new feature of xterm. I can only
+   speculate that initscreen() and endwin() must send some kind of
+   special escape sequences that command xterm to save and restore the
+   screen. To defeat this effect, tell Linux you have a vt100 or other
+   xterm-compatible terminal that is not actually an xterm, or else tell
+   Kermit to SET TRANSFER DISPLAY to something besides FULLSCREEN.
+    ________________________________________________________________________
+
+  3.4. C-KERMIT AND NEXTSTEP
+
+   [ [331]Top ] [ [332]Contents ] [ [333]Section Contents ] [ [334]Next ]
+   [ [335]Previous ]
+
+   Run C-Kermit in a Terminal, Stuart, or xterm window, or when logged in
+   remotely through a serial port or TELNET connection. C-Kermit does not
+   work correctly when invoked directly from the NeXTSTEP File Viewer or
+   Dock. This is because the terminal-oriented gtty, stty, & ioctl calls
+   don't work on the little window that NeXTSTEP pops up for non-NeXTSTEP
+   applications like Kermit. CBREAK and No-ECHO settings do not take
+   effect in the command parser -- commands are parsed strictly line at a
+   time. "set line /dev/cua" works. During CONNECT mode, the console
+   stays in cooked mode, so characters are not transmitted until carriage
+   return or linefeed is typed, and you can't escape back. If you want to
+   run Kermit directly from the File Viewer, then launch it from a shell
+   script that puts it in the desired kind of window, something like this
+   (for "Terminal"):
+
+  Terminal -Lines 24 -Columns 80 -WinLocX 100 -WinLocY 100 $FONT $FONTSIZE \
+  -SourceDotLogin -Shell /usr/local/bin/kermit &
+
+   C-Kermit does not work correctly on a NeXT with NeXTSTEP 3.0 to which
+   you have established an rlogin connection, due to a bug in NeXTSTEP
+   3.0, which has been reported to NeXT.
+
+   The SET CARRIER command has no effect on the NeXT -- this is a
+   limitation of the NeXTSTEP serial-port device drivers.
+
+   Hardware flow control on the NeXT is selected not by "set flow
+   rts/cts" in Kermit (since NeXTSTEP offers no API for this), but
+   rather, by using a specially-named driver for the serial device:
+   /dev/cufa instead /dev/cua; /dev/cufb instead of /dev/cub. This is
+   available only on 68040-based NeXT models (the situation for Intel
+   NeXTSTEP implementations is unknown).
+
+   NeXT-built 68030 and 68040 models have different kinds of serial
+   interfaces; the 68030 has a Macintosh-like RS-422 interface, which
+   lacks RTS and CTS signals; the 68040 has an RS-423 (RS-232 compatible)
+   interface, which supports the commonly-used modem signals. WARNING:
+   the connectors look exactly the same, but the pins are used in
+   completely DIFFERENT ways -- different cables are required for the two
+   kinds of interfaces.
+
+     IF YOU GET LOTS OF RETRANSMISSIONS during file transfer, even when
+     using a /dev/cuf* device and the modem is correctly configured for
+     RTS/CTS flow control, YOU PROBABLY HAVE THE WRONG KIND OF CABLE.
+
+   On the NeXT, Kermit reportedly (by TimeMon) causes the kernel to use a
+   lot of CPU time when using a "set line" connection. That's because
+   there is no DMA channel for the NeXT serial port, so the port must
+   interrupt the kernel for each character in or out.
+
+   One user reported trouble running C-Kermit on a NeXT from within
+   NeXT's Subprocess class under NeXTstep 3.0, and/or when rlogin'd from
+   one NeXT to another: Error opening /dev/tty:, congm: No such device or
+   address. Diagnosis: Bug in NeXTSTEP 3.0, cure unknown.
+    ________________________________________________________________________
+
+  3.5. C-KERMIT AND QNX
+
+   [ [336]Top ] [ [337]Contents ] [ [338]Section Contents ] [ [339]Next ]
+   [ [340]Previous ]
+
+   See also: The [341]comp.os.qnx newsgroup.
+
+   Support for QNX 4.x was added in C-Kermit 5A(190). This is a
+   full-function implementation, thoroughly tested on QNX 4.21 and later,
+   and verified to work in both 16-bit and 32-bit versions. The 16-bit
+   version was dropped in C-Kermit 7.0 since it can no longer be built
+   successfully (after stripping most most features, I succeeded in
+   getting it to compile and link without complaint, but the executable
+   just beeps when you run it); for 16-bit QNX 4.2x, use C-Kermit 6.0 or
+   earlier, or else [342]G-Kermit.
+
+   The 32-bit version (and the 16-bit version prior to C-Kermit 7.0)
+   supports most of C-Kermit's advanced features including TCP/IP, high
+   serial speeds, hardware flow-control, modem-signal awareness, curses
+   support, etc.
+
+   BUG: In C-Kermit 6.0 on QNX 4.22 and earlier, the fullscreen file
+   transfer display worked fine the first time, but was fractured on
+   subsequent file transfers. Cause and cure unknown. In C-Kermit 7.0 and
+   QNX 4.25, this no longer occurs. It is not known if it would occur in
+   C-Kermit 7.0 or later on earlier QNX versions.
+
+   Dialout devices are normally /dev/ser1, /dev/ser2, ..., and can be
+   opened explicitly with SET LINE. Reportedly, "/dev/ser" (no unit
+   number) opens the first available /dev/sern device.
+
+   Like all other Unix C-Kermit implementations, QNX C-Kermit does not
+   provide any kind of terminal emulation. Terminal specific functions
+   are provided by your terminal, terminal window (e.g. QNX Terminal or
+   xterm), or emulator.
+
+   QNX C-Kermit, as distributed, does not include support for UUCP
+   line-locking; the QNX makefile entries (qnx32 and qnx16) include the
+   -DNOUUCP switch. This is because QNX, as distributed, does not include
+   UUCP, and its own communications software (e.g. qterm) does not use
+   UUCP line locking. If you have a UUCP product installed on your QNX
+   system, remove the -DNOUUCP switch from the makefile entry and
+   rebuild. Then check to see that Kermit's UUCP lockfile conventions are
+   the same as those of your UUCP package; if not, read the [343]UUCP
+   lockfile section of the [344]Installation Instructions and make the
+   necessary changes to the makefile entry (e.g. add -DHDBUUCP).
+
+   QNX does, however, allow a program to get the device open count. This
+   can not be a reliable form of locking unless all applications do it,
+   so by default, Kermit uses this information only for printing a
+   warning message such as:
+
+  C-Kermit>set line /dev/ser1
+  WARNING - "/dev/ser1" looks busy...
+
+   However, if you want to use it as a lock, you can do so with:
+
+  SET QNX-PORT-LOCK { ON, OFF }
+
+   This is OFF by default; if you set in ON, C-Kermit will fail to open
+   any dialout device when its open count indicates that another process
+   has it open. SHOW COMM (in QNX only) displays the setting, and if you
+   have a port open, it also shows the open count.
+
+   As of C-Kermit 8.0, C-Kermit's "open-count" form of line locking works
+   only in QNX4, not in QNX6 (this might change in a future C-Kermit
+   release).
+    ________________________________________________________________________
+
+  3.6. C-KERMIT AND SCO
+
+   [ [345]Top ] [ [346]Contents ] [ [347]Section Contents ] [ [348]Next ]
+   [ [349]Previous ]
+
+   SECTION CONTENTS
+
+3.6.1. [350]SCO XENIX
+3.6.2. [351]SCO UNIX and OSR5
+3.6.3. [352]Unixware
+3.6.4. [353]Open UNIX 8
+
+   REFERENCES
+
+     * The comp.unix.sco.* newsgroups.
+     * [354]Section 3.10 below for Unixware.
+     * The following FAQs:
+
+        The comp.sco.misc FAQ:
+                [355]http://aplawrence.com/SCOFAQ/
+
+        Caldera (SCO) comp.unix.sco.programmer FAQ:
+                [356]http://www.zenez.com/cgi-bin/scoprogfaq/faq.pl
+
+        The UnixWare 7/OpenUNIX 8 FAQ:
+                [357]http://www.zenez.com/cgi-bin/scouw7faq/faq.pl
+                [358]http://zenez.pcunix.com/cgi-bin/scouw7faq/faq.pl
+
+        High Speed Modems for SCO Unix:
+                [359]http://pcunix.com/Unixart/modems.html
+
+        The UnixWare FAQ
+                [360]http://www.freebird.org/faq/
+
+        The UnixWare 1.x and 2.0 Programmer FAQ
+                [361]http://www.freebird.org/faq/developer.html
+
+        Caldera Support Knowledge Base
+                [362]http://support.caldera.com/caldera
+
+        [363]http://stage.caldera.com/ta/
+                Caldera (SCO) Technical Article Search Center
+
+        [364]http://aplawrence.com/newtosco.html
+                New to SCO (Tony Lawrence)
+
+   The same comments regarding terminal emulation and key mapping apply
+   to SCO operating systems as to all other Unixes. C-Kermit is not a
+   terminal emulator, and you can't use it to map F-keys, Arrow keys,
+   etc. The way to do this is with xmodmap (xterm) or loadkeys (console).
+   For a brief explanation, see [365]Section 3.0.5. For a fuller
+   explanation, [366]ClICK HERE.
+
+   Also see general comments on PC-based Unixes in [367]Section 3.0.
+
+  3.6.1. SCO XENIX
+
+   [ [368]Top ] [ [369]Contents ] [ [370]Section Contents ] [ [371]Next ]
+
+   Old Xenix versions... Did you know: Xenix 3.0 is *older* than Xenix
+   2.0?
+
+   In Xenix 2.3.4 and probably other Xenix versions, momentarily dropping
+   DTR to hang up a modem does not work. DTR goes down but does not come
+   up again. Workaround: Use SET MODEM HANGUP-METHOD MODEM-COMMAND.
+   Anybody who would like to fix this is welcome to take a look at
+   tthang() in [372]ckutio.c. Also: modem signals can not be read in
+   Xenix, and the maximum serial speed is 38400.
+
+   There is all sorts of confusion among SCO versions, particularly when
+   third- party communications boards and drivers are installed,
+   regarding lockfile naming conventions, as well as basic functionality.
+   As far as lockfiles go, all bets are off if you are using a
+   third-party multiport board. At least you have the source code.
+   Hopefully you also have a C compiler :-)
+
+   Xenix 2.3.0 and later claim to support RTSFLOW and CTSFLOW, but this
+   is not modern bidirectional hardware flow control; rather it
+   implements the original RS-232 meanings of these signals for
+   unidirectional half-duplex line access: If both RTSFLOW and CTSFLOW
+   bits are set, Xenix asserts RTS when it wants to send data and waits
+   for CTS assertion before it actually starts sending data (also,
+   reportedly, even this is broken in Xenix 2.3.0 and 2.3.1).
+    ________________________________________________________________________
+
+  3.6.2. SCO UNIX AND OSR5
+
+   [ [373]Top ] [ [374]Contents ] [ [375]Section Contents ] [ [376]Next ]
+   [ [377]Previous ]
+
+   SCO systems tend to use different names (i.e. drivers) for the same
+   device. Typically /dev/tty1a refers to a terminal device that has no
+   modem control; open, read, write, and close operations do not depend
+   on carrier. On the other hand, /dev/tty1A (same name, but with final
+   letter upper case), is the same device with modem control, in which
+   carrier is required (the SET LINE command does not complete until
+   carrier appears, read/write operations fail if there is no carrier,
+   etc).
+
+   SCO OpenServer 5.0.5 and earlier do not support the reading of modem
+   signals. Thus "show comm" does not list modem signals, and C-Kermit
+   does not automatically pop back to its prompt when the modem hangs up
+   the connection (drops CD). The ioctl() call for this is simply not
+   implmented, at least not in the standard drivers. OSR5.0.6 attempts to
+   deal with modem signals but fails; however OSR5.0.6a appears to
+   function properly.
+
+   Dialing is likely not to work well in SCO OpenServer 5.0.x because
+   many of the serial-port APIs simply do not operate when using the
+   standard drivers. For example, if DTR is dropped by the recommended
+   method (setting speed to 0 for half a seconds, then restoring the
+   speed), DTR and RTS go down but never come back up. When in doubt SET
+   MODEM HANGUP-METHOD MODEM-COMMAND or SET DIAL HANGUP OFF.
+
+   On the other hand, certain functions that might not (do not) work
+   right or at all when using SCO drivers (e.g. high serial speeds,
+   hardware flow control, and/or reading of modem signals) might work
+   right when using third-party drivers. (Example: hardware flow control
+   works, reportedly, only on uppercase device like tty1A -- not tty1a --
+   and only when CLOCAL is clear when using the SCO sio driver, but there
+   are no such restrictions in, e.g., [378]Digiboard drivers).
+
+   One user reports that he can't transfer large files with C-Kermit
+   under SCO OSR5.0.0 and 5.0.4 -- after the first 5K, everything falls
+   apart. Same thing without Kermit -- e.g. with ftp over a PPP
+   connection. Later, he said that replacing SCO's SIO driver with FAS,
+   an alternative communications driver, made the problem go away:
+
+  [379]ftp://ftp.fu-berlin.de/pub/unix/driver/fas
+
+   With regard to bidirectional serial ports on OpenServer 5.0.4, the
+   following advice appeared on an SCO-related newsgroup:
+
+     No amount of configuration information is going to help you on
+     5.0.4 unless it includes the kludge for the primary problem. With
+     almost every modem, the 5.0.4 getty will barf messages and may or
+     may not connect. There are 2 solutions and only one works on 5.0.4.
+     Get the atdialer binary from a 5.0.0 system and substitute it for
+     the native 5.0.4 atdialer. The other solution is to upgrade to
+     5.0.5. And, most of all, on any OpenServer products, do NOT run the
+     badly broken Modem Manager. Configure the modems in the time
+     honored way that dates back to Xenix.
+
+   Use SCO-provided utilities for switching the directionality of a modem
+   line, such as "enable" and "disable" commands. For example, to dial
+   out on tty1a, which is normally set up for logins:
+
+  disable tty1a
+  kermit -l /dev/tty1a
+  enable tty1a
+
+   If a tty device is listed as an ACU in /usr/lib/uucp/Devices and is
+   enabled, getty resets the ownership and permissions to uucp.uucp and
+   640 every time the device is released. If you want to use the device
+   only for dialout, and you want to specify other owners or permissions,
+   you should disable it in /usr/lib/uucp/Devices; this will prevent
+   getty from doing things to it. You should also changes the device's
+   file modes in /etc/conf/node.d/sio by changing fields 5-7 for the
+   desired device(s); this determines how the devices are set if you
+   relink the kernel.
+
+   One SCO user of C-Kermit 5A(190) reported that only one copy of Kermit
+   can run at a time when a Stallion Technologies multiport boards are
+   installed. Cause, cure, and present status unknown (see [380]Section
+   14 for more info regarding Stallion).
+
+   Prior to SCO OpenServer 5.0.4, the highest serial port speed supported
+   by SCO was 38400. However, in some SCO versions (e.g. OSR5) it is
+   possible to map rarely-used lower speeds (like 600 and 1800) to higher
+   ones like 57600 and 115200. To find out how, go to
+   [381]http://www.sco.com/ and search for "115200". In OSR5.0.4, serial
+   speeds up to 921600 are supported through the POSIX interface;
+   C-Kermit 6.1.193 or later, when built for OSR5.0.4 using /bin/cc (NOT
+   the UDK, which hides the high-speed definitions from CPP), supports
+   these speeds, but you might be able to run this binary on earlier
+   releases to get the high serial speeds, depending on various factors,
+   described by Bela Lubkin of SCO:
+
+  Serial speeds under SCO Unix / Open Desktop / OpenServer
+  ========================================================
+  Third party drivers (intelligent serial boards) may provide any speeds
+  they desire; most support up to 115.2Kbps.
+
+  SCO's "sio" driver, which is used to drive standard serial ports with
+  8250/16450/16550 and similar UARTs, was limited to 38400bps in older
+  releases.  Support for rates through 115.2Kbps was added in the
+  following releases:
+
+    SCO OpenServer Release 5.0.0 (requires supplement "rs40b")
+    SCO OpenServer Release 5.0.2 (requires supplement "rs40a" or "rs40b")
+    SCO OpenServer Release 5.0.4 or later
+    SCO Internet FastStart Release 1.0.0 or later
+
+   SCO supplements are at [382]ftp://ftp.sco.com/; the "rs40" series are
+   under directory /Supplements/internet
+
+   Kermit includes the high serial speeds in all OSR5 builds, but that
+   does not necessarily mean they work. For example, on our in-house
+   5.0.5 system, SET SPEED 57600 or higher seems to succeed (no error
+   occurs) but when we read the speed back the driver says it is 50.
+   Similarly, 76800 becomes 75, and 115200 becomes 110. Testing shows the
+   resulting speed is indeed the low one we read back, not the high one
+   we asked for. Moral: Use speeds higher than 38400 with caution on SCO
+   OSR5.
+
+   Reportedly, if you have a script that makes a TCP/IP SET HOST (e.g.
+   Telnet) connection to SCO 3.2v4.2 with TCP/IP 1.2.1, and then does the
+   following:
+
+  script $ exit
+  hangup
+
+   this causes a pseudoterminal (pty) to be consumed on the SCO system;
+   if you do it enough times, it will run out of ptys. An "exit" command
+   is being sent to the SCO shell, and a HANGUP command is executed
+   locally, so the chances are good that both sides are trying to close
+   the connection at once, perhaps inducing a race condition in which the
+   remote pty is not released. It was speculated that this would be fixed
+   by applying SLS net382e, but it did not. Meanwhile, the workaround is
+   to insert a "pause" between the SCRIPT and HANGUP commands. (The
+   situation with later SCO releases is not known.)
+
+   SCO UNIX and OpenServer allow their console and/or terminal drivers to
+   be configured to translate character sets for you. DON'T DO THIS WHEN
+   USING KERMIT! First of all, you don't need it -- Kermit itself already
+   does this for you. And second, it will (a) probably ruin the
+   formatting of your screens (depending on which emulation you are
+   using); and (b) interfere with all sorts of other things -- legibility
+   of non-ASCII text on the terminal screen, file transfer, etc. Use:
+
+  mapchan -n
+
+   to turn off this feature.
+
+   Note that there is a multitude of SCO entries in the makefile, many of
+   them exhibiting an unusually large number of compiler options. Some
+   people actually understand all of this. Reportedly, things are
+   settling down with SCO OpenServer 5.x and Unixware 7 (and Open UNIX 8
+   and who knows what the next one will be -- Linux probably) -- the SCO
+   UDK compiler is said to generate binaries that will run on either
+   platform, by default, automatically. When using gcc or egcs, on the
+   other hand, differences persist, plus issues regarding the type of
+   binary that is generated (COFF, ELF, etc), and where and how it can
+   run. All of this could stand further clarification by SCO experts.
+    ________________________________________________________________________
+
+  3.6.3. Unixware
+
+   [ [383]Top ] [ [384]Contents ] [ [385]Section Contents ] [ [386]Next ]
+   [ [387]Previous ]
+
+   Unixware changed hands several times before landing at SCO, and so has
+   its [388]own section in this document. (Briefly: AT&T UNIX Systems
+   Laboratories sold the rights to the UNIX name and to System V R4 (or
+   R5?) to Novell; later Novell spun its UNIX division off into a new
+   company called Univel, which eventually was bought by SCO, which later
+   was bought by Caldera, which later sort of semi-spun-off SCO...)
+    ________________________________________________________________________
+
+  3.6.4. Open UNIX 8
+
+   [ [389]Top ] [ [390]Contents ] [ [391]Section Contents ] [
+   [392]Previous ]
+
+   SCO was bought by Caldera in 2000 or 2001 and evolved Unixware 7.1
+   into Caldera Open UNIX 8.00. It's just like Unixware 7.1 as far as
+   Kermit is concerned (the Unixware 7.1 makefile target works for Open
+   UNIX 8.00, and in fact a Unixware 7.1 Kermit binary built on Unixware
+   7.1 runs under OU8; a separate OU8 makefile target exists simply to
+   generate an appropriate program startup herald). Open Unix is now
+   defunct; subsequent releases are called UnixWare again (e.g. UnixWare
+   7.1.3).
+    ________________________________________________________________________
+
+  3.7. C-KERMIT AND SOLARIS
+
+   [ [393]Top ] [ [394]Contents ] [ [395]Section Contents ] [ [396]Next ]
+   [ [397]Previous ]
+
+   SECTION CONTENTS
+
+3.7.1. [398]Serial Port Configuration
+3.7.2. [399]Serial Port Problems
+3.7.3. [400]SunLink X.25
+3.7.4. [401]Sun Workstation Keyboard Mapping
+3.7.5. [402]Solaris 2.4 and Earlier
+
+   REFERENCES
+
+     * The [403]comp.unix.solaris newsgroup
+     * [404]http://access1.sun.com/
+     * [405]http://docs.sun.com/
+     * [406]http://www.sunhelp.com/
+     * [407]http://www.wins.uva.nl/pub/solaris/solaris2/
+     * [408]http://www.wins.uva.nl/cgi-bin/sfaq.cgi
+     * [409]ftp://ftp.wins.uva.nl/pub/solaris
+     * [410]http://www.science.uva.nl/pub/solaris/solaris2.html
+
+   And about serial communications in particular, see "Celeste's Tutorial
+   on Solaris 2.x Modems and Terminals":
+
+  [411]http://www.stokely.com/
+
+   In particular:
+
+  [412]http://www.stokely.com/unix.sysadm.resources/faqs.sun.html
+
+   For PC-based Solaris, also see general comments on PC-based Unixes in
+   [413]Section 3.0. Don't expect Solaris or any other kind of Unix to
+   work right on a PC until you resolve all interrupt conflicts. Don't
+   expect to be able to use COM3 or COM4 (or even COM2) until you have
+   configured their addresses and interrupts.
+    ________________________________________________________________________
+
+  3.7.1. Serial Port Configuration
+
+   [ [414]Top ] [ [415]Contents ] [ [416]Section Contents ] [
+   [417]Section Contents ] [ [418]Next ]
+
+   Your serial port can't be used -- or at least won't work right --
+   until it is enabled in Solaris. For example, you get a message like
+   "SERIAL: Operation would block" when attempting to dial. This probably
+   indicates that the serial port has not been enabled for use with
+   modems. You'll need to follow the instructions in your system setup or
+   management manual, such as (e.g.) the Desktop SPARC Sun System &
+   Network Manager's Guide, which should contain a section "Setting up
+   Modem Software"; read it and follow the instructions. These might (or
+   might not) include running a program called "eeprom", editing some
+   system configuration file (such as, for example:
+
+  /platform/i86pc/kernel/drv/asy.conf
+
+   and then doing a configuration reboot, or running some other programs
+   like drvconfig and devlinks. "man eeprom" for details.
+
+   Also, on certain Sun models like IPC, the serial port hardware might
+   need to have a jumper changed to make it an RS-232 port rather than
+   RS-423.
+
+   eeprom applies only to real serial ports, not to "Spiff" devices
+   (serial port expander), in which case setup with Solaris' admintool is
+   required.
+
+   Another command you might need to use is pmadm, e.g.:
+
+  pmadm -d -p zsmon -s tty3
+  pmadm -e -p zsmon -s tty3
+
+   You can use the following command to check if a process has the device
+   open:
+
+  fuser -f /dev/term/3
+
+   In some cases, however (according to Sun support, May 2001) "It is
+   still possible that a zombie process has hold of the port EVEN IF
+   there is no lock file and the fuser command comes up empty. In that
+   case, the only way to resolve the problem is by rebooting."
+
+   If you can't establish communication through a serial port to a device
+   that is not asserting CD (Carrier Detect), try setting the environment
+   variable "ttya-ignore-cd" to "true" (replace "ttya" with the port
+   name).
+    ________________________________________________________________________
+
+  3.7.2. Serial Port Problems
+
+   [ [419]Top ] [ [420]Contents ] [ [421]Section Contents ] [ [422]Next ]
+   [ [423]Previous ]
+
+   Current advice from Sun is to always the /dev/cua/x devices for
+   dialing out, rather than the /dev/term/x. Nevertheless, if you have
+   trouble dialing out with one, try the other.
+
+   Reportedly, if you start C-Kermit and "set line" to a port that has a
+   modem connected to it that is not turned on, and then "set flow
+   rts/cts", there might be some (unspecified) difficulties closing the
+   device because the CTS signal is not coming in from the modem.
+    ________________________________________________________________________
+
+  3.7.3. SunLink X.25
+
+   [ [424]Top ] [ [425]Contents ] [ [426]Section Contents ] [ [427]Next ]
+   [ [428]Previous ]
+
+   The built-in SunLink X.25 support for Solaris 2.3/2.4./25 and SunLink
+   8.01 or 9.00 works OK provided the X.25 system has been installed and
+   initialized properly. Packet sizes might need to be reduced to 256,
+   maybe even less, depending on the configuration of the X.25
+   installation. On one connection where C-Kermit 6.0 was tested, very
+   large packets and window sizes could be used in one direction, but
+   only very small ones would work in the other.
+
+   In any case, according to Sun, C-Kermit's X.25 support is superfluous
+   with SunLink 8.x / Solaris 2.3. Quoting an anonymous Sun engineer:
+
+     ... there is now no need to include any X.25 code within kermit. As
+     of X.25 8.0.1 we support the use of kermit, uucp and similar
+     protocols over devices of type /dev/xty. This facility was there in
+     8.0, and should also work on the 8.0 release if patch 101524 is
+     applied, but I'm not 100% sure it will work in all cases, which is
+     why we only claim support from 8.0.1 onwards.
+
+     When configuring X.25, on the "Advanced Configuration->Parameters"
+     screen of the x25tool you can select a number of XTY devices. If
+     you set this to be > 1, press Apply, and reboot, you will get a
+     number of /dev/xty entries created.
+
+     Ignore /dev/xty0, it is a special case. All the others can be used
+     exactly as if they were a serial line (e.g. /dev/tty) connected to
+     a modem, except that instead of using Hayes-style commands, you use
+     PAD commands.
+
+     From kermit you can do a 'set line' command to, say, /dev/xty1,
+     then set your dialing command to be "CALL 12345678", etc. All the
+     usual PAD commands will work (SET, PAR, etc).
+
+     I know of one customer in Australia who is successfully using this,
+     with kermit scripts, to manage some X.25-connected switches. He
+     used standard kermit, compiled for Solaris 2, with X.25 8.0 xty
+     devices.
+    ________________________________________________________________________
+
+  3.7.4. Sun Workstation Keyboard Mapping
+
+   [ [429]Top ] [ [430]Contents ] [ [431]Section Contents ] [ [432]Next ]
+   [ [433]Previous ]
+
+   Hints for using a Sun workstation keyboard for VT emulation when
+   accessing VMS, from the [434]comp.os.vms newsgroup:
+
+     From: Jerry Leichter <leichter@smarts.com>
+     Newsgroups: comp.os.vms
+     Subject: Re: VT100 keyboard mapping to Sun X server
+     Date: Mon, 19 Aug 1996 12:44:21 -0400
+
+     > I am stuck right now using a Sun keyboard (type 5) on systems
+     running SunOS
+     > and Solaris. I would like to use EVE on an OpenVMS box with
+     display back to
+     > the Sun. Does anyone know of a keyboard mapping (or some other
+     procedure)
+     > which will allow the Sun keyboard to approximate a VT100/VT220?
+
+     You can't get it exactly - because the keypad has one fewer key -
+     but you can come pretty close. Here's a set of keydefs I use:
+
+  keycode 101=KP_0
+  keycode 119=KP_1
+  keycode 120=KP_2
+  keycode 121=KP_3
+  keycode 98=KP_4
+  keycode 99=KP_5
+  keycode 100=KP_6
+  keycode 75=KP_7
+  keycode 76=KP_8
+  keycode 77=KP_9
+  keycode 52=KP_F1
+  keycode 53=KP_F2
+  keycode 54=KP_F3
+  keycode 57=KP_Decimal
+  keycode 28=Left
+  keycode 29=Right
+  keycode 30=KP_Separator
+  keycode 105=KP_F4
+  keycode 78=KP_Subtract
+  keycode 8=Left
+  keycode 10=Right
+  keycode 32=Up
+  keycode 33=Down
+  keycode 97=KP_Enter
+
+     Put this in a file - I use "keydefs" in my home directory and feed
+     it into xmodmap:
+
+  xmodmap - <$HOME/keydefs
+
+     This takes care of the arrow keys and the "calculator" key cluster.
+     The "+" key will play the role of the DEC "," key. The Sun "-" key
+     will be like the DEC "-" key, though it's in a physically different
+     position - where the DEC PF4 key is. The PF4 key is ... damn, I'm
+     not sure where "key 105" is. I *think* it may be on the leftmost
+     key of the group of four just above the "calculator" key cluster.
+
+     I also execute the following (this is all in my xinitrc file):
+
+  xmodmap -e 'keysym KP_Decimal = KP_Decimal'
+  xmodmap -e 'keysym BackSpace = Delete BackSpace' \
+          -e 'keysym Delete = BackSpace Delete'
+  xmodmap -e 'keysym KP_Decimal = Delete Delete KP_Decimal'
+  xmodmap -e 'add mod1 = Meta_R'
+  xmodmap -e 'add mod1 = Meta_L'
+
+     Beware of one thing about xmodmap: Keymap changes are applied to
+     the *whole workstation*, not just to individual windows. There is,
+     in fact, no way I know of to apply them to individual windows.
+     These definitions *may* confuse some Unix programs (and/or some
+     Unix users).
+
+     If you're using Motif, you may also need to apply bindings at the
+     Motif level. If just using xmodmap doesn't work, I can try and dig
+     that stuff up for you.
+    ________________________________________________________________________
+
+  3.7.5. Solaris PPP Connections
+
+   [ [435]Top ] [ [436]Contents ] [ [437]Section Contents ] [ [438]Next ]
+   [ [439]Previous ]
+
+   The following is a report from a user of C-Kermit 8.0 on Solaris 8 and
+   9, who had complained that while Kermit file transfers worked
+   perfectly on direct (non-PPP) dialout connections, they failed
+   miserably on PPP connections. We suggested that the PPP dialer
+   probably was not setting the port and/or modem up in the same way that
+   Kermit did:
+
+     I want to get back on this and tell you what the resolution was.
+     You pointed me in the direction of flow control, which turned out
+     to be the key.
+
+     Some discussion on the comp.unix.solaris newsgroup led to some
+     comments from Greg Andrews about the need to use the uucp driver to
+     talk to the modem (/dev/cua/a). I had to remind Greg that no matter
+     what the manpages for the zs and se drivers say, the ppp that Sun
+     released with Solaris 8 7/01, and has in Solaris 9, is a setuid
+     root program, and simply trying to make a pppd call from user space
+     specifying /dev/cua/a would fail because of permissions. Greg
+     finally put the question to the ppp people, who came back with
+     information that is not laid out anywhere in the docs available for
+     Solaris users. Namely, put /dev/cua/a in one of the priviledged
+     options files in the /etc/ppp directory. That, plus resetting the
+     OBP ttya-ignore-cd flag (this is Sun hardware) to false, seems to
+     have solved the problems.
+
+     While I note that I had installed Kermit suid to uucp to use
+     /dev/cua/a on this particular box, it seems to run fine through
+     /dev/term/a. Not so with pppd.
+
+     With this change in place, I seem to be able to upload and download
+     through telnet run on Kermit with the maximum length packets. I
+     note that the window allocation display does show STREAMING, using
+     telnet. Running ssh on Kermit, I see the standard 1 of 30 windows
+     display, and note that there appears to be a buffer length limit
+     between 1000 and 2000 bytes. Run with 1000, and it's tick-tock,
+     solid as a rock. With 2000 I see timeout errors and RTS/CTS action
+     on the modem.
+
+   Kermit's packet-length and other controls let you make adjustments
+   like this to get around whatever obstacles might be thrown up -- in
+   this case (running Kermit over ssh), the underling Solaris PTY driver.
+    ________________________________________________________________________
+
+  3.7.6. Solaris 2.4 and Earlier
+
+   [ [440]Top ] [ [441]Contents ] [ [442]Section Contents ] [
+   [443]Previous ]
+
+   C-Kermit can't be compiled successfully under Solaris 2.3 using
+   SUNWspro cc 2.0.1 unless at least some of the following patches are
+   applied to cc (it is not known which one(s), if any, fix the problem):
+
+     * 100935-01 SparcCompiler C 2.0.1: bad code generated when addresses
+       of two double arguments are involved
+     * 100961-05 SPARCcompilers C 2.0.1: conditional expression with
+       function returning structure gives wrong value
+     * 100974-01 SparcWorks 2.0.1: dbx jumbo patch
+     * 101424-01 SPARCworks 2.0.1 maketool SEGV's instantly on Solaris
+       2.3
+
+   With unpatched cc 2.0.1, the symptom is that certain modules generate
+   truncated object files, resulting in many unresolved references at
+   link time.
+
+     The rest of the problems in this section have to do with
+     bidirectional terminal ports and the Solaris Port Monitor. A bug in
+     C-Kermit 5A ticked a bug in Solaris. The C-Kermit bug was fixed in
+     version 6.0, and the Solaris bug was fixed in 2.4 (I think, or
+     maybe 2.5). 
+
+   Reportedly, "C-Kermit ... causes a SPARCstation running Solaris 2.3 to
+   panic after the modem connects. I have tried compiling C-Kermit with
+   Sun's unbundled C compiler, with GCC Versions 2.4.5 and 2.5.3, with
+   make targets 'sunos51', 'sunos51tcp', 'sunos51gcc', and even 'sys5r4',
+   and each time it compiles and starts up cleanly, but without fail, as
+   soon as I dial the number and get a 'CONNECT' message from the modem,
+   I get:
+
+  BAD TRAP
+  kermit: Data fault
+  kernel read fault at addr=0x45c, pme=0x0
+  Sync Error Reg 80 <INVALID>
+  ...
+  panic: Data Fault.
+  ...
+  Rebooting...
+
+   The same modem works fine for UUCP/tip calling." Also (reportedly),
+   this only happens if the dialout port is configured as in/out via
+   admintool. If it is configured as out-only, no problem. This is the
+   same dialing code that works on hundreds of other System-V based Unix
+   OS's. Since it should be impossible for a user program to crash the
+   operating system, this problem must be chalked up to a Solaris bug.
+   Even if you SET CARRIER OFF, CONNECT, and dial manually by typing
+   ATDTnnnnnnn, the system panics as soon as the modem issues its CONNECT
+   message. (Clearly, when you are dialing manually, C-Kermit does not
+   know a thing about the CONNECT message, and so the panic is almost
+   certainly caused by the transition of the Carrier Detect (CD) line
+   from off to on.) This problem was reported by many users, all of whom
+   say that C-Kermit worked fine on Solaris 2.1 and 2.2. If the
+   speculation about CD is true, then a possible workaround might be to
+   configure the modem to leave CD on (or off) all the time. Perhaps by
+   the time you read this, a patch will have been issued for Solaris 2.3.
+
+   The following is from Karl S. Marsh, Systems & Networks Administrator,
+   AMBIX Systems Corp, Rochester, NY:
+
+     Environment: Solaris 2.3 Patch 101318-45 C-Kermit 5A(189) (and
+     presumably this applies to 188 and 190 also). eeprom setting:
+
+  ttya-rts-dtr-off=false
+  ttya-ignore-cd=false
+  ttya-mode=19200,8,n,8,-
+
+     To use C-Kermit on a bidirectional port in this environment, do not
+     use admintool to configure the port. Use admintool to delete any
+     services running on the port and then quit admintool and issue the
+     following command:
+
+  pmadm -a -p zsmon -s ttyb -i root -fu -v 1 -m "`ttyadm -b -d /dev/term/b \
+  -l conttyH -m ldterm,ttcompat -s /usr/bin/login -S n`"
+
+     [NOTE: This was copied from a blurry fax, so please check it
+     carefully] where:
+
+  -a = Add service
+  -p = pmtag (zsmon)
+  -s = service tag (ttyb)
+  -i = id to be associated with service tag (root)
+  -fu = create utmp entry
+  -v = version of ttyadm
+  -m = port monitor-specific portion of the port monitor administrative file
+       entry for the service
+  -b = set up port for bidirectional use
+  -d = full path name of device
+  -l = which ttylabel in the /etc/ttydefs file to use
+  -m = a list of pushable STREAMS modules
+  -s = pathname of service to be invoked when connection request received
+  -S = software carrier detect on or off (n = off)
+
+     "This is exactly how I was able to get Kermit to work on a
+     bi-directional port without crashing the system."
+
+   On the Solaris problem, also see SunSolve Bug ID 1150457 ("Using
+   C-Kermit, get Bad Trap on receiving prompt from remote system").
+   Another user reported "So, I have communicated with the Sun tech
+   support person that submitted this bug report [1150457]. Apparently,
+   this bug was fixed under one of the jumbo kernel patches. It would
+   seem that the fix did not live on into 101318-45, as this is EXACTLY
+   the error that I see when I attempt to use kermit on my system."
+
+   Later (Aug 94)... C-Kermit dialout successfully tested on a Sun4m with
+   a heavily patched Solaris 2.3. The patches most likely to have been
+   relevant:
+
+     * 101318-50: SunOS 5.3: Jumbo patch for kernel (includes libc,
+       lockd)
+     * 101720-01: SunOS 5.3: ttymon - prompt not always visible on a
+       modem connection
+     * 101815-01: SunOS 5.3: Data fault in put() NULL queue passed from
+       ttycommon_qfull()
+     * 101328-01: SunOS 5.3: Automation script to properly setup tty
+       ports prior to PCTS execution
+
+   Still later (Nov 94): another user (Bo Kullmar in Sweden) reports that
+   after using C-Kermit to dial out on a bidirectional port, the port
+   might not answer subsequent incoming calls, and says "the problem is
+   easy enough to fix with the Serial Port Manager; I just delete the
+   service and install it again using the graphical interface, which
+   underneath uses commands like sacadm and pmadm." Later Bo reports, "I
+   have found that if I run Kermit with the following script then it
+   works. This script is for /dev/cua/a, "-s a" is the last a in
+   /dev/cua/a:
+
+  #! /bin/sh
+  kermit
+  sleep 2
+  surun pmadm -e -p zsmon -s a
+    ________________________________________________________________________
+
+  3.8. C-KERMIT AND SUNOS
+
+   [ [444]Top ] [ [445]Contents ] [ [446]Section Contents ] [ [447]Next ]
+   [ [448]Previous ]
+
+   For additional information, see "Celeste's Tutorial on SunOS 4.1.3+
+   Modems and Terminals":
+
+  [449]http://www.stokely.com/
+
+   For FAQs, etc, from Sun, see:
+     * [450]http://access1.sun.com/
+
+   For history of Sun models and SunOS versions, see (should be all the
+   same):
+     * [451]http://www.ludd.luth.se/~bear/project/sun/sun.hardware.txt
+     * [452]ftp://ftp.netcom.com/pub/ru/rubicon/sun.hdwr.ref
+     * [453]ftp://ftp.intnet.net/pub/SUN/Sun-Hardware-Ref
+
+   Sun SPARCstation users should read the section "Setting up Modem
+   Software" in the Desktop SPARC Sun System & Network Manager's Guide.
+   If you don't set up your serial ports correctly, Kermit (and other
+   communications software) won't work right.
+
+   Also, on certain Sun models like IPC, the serial port hardware might
+   need to have a jumper changed to make it an RS-232 port rather than
+   RS-423.
+
+   Reportedly, C-Kermit does not work correctly on a Sun SPARCstation in
+   an Open Windows window with scrolling enabled. Disable scrolling, or
+   else invoke Kermit in a terminal emulation window (xterm, crttool,
+   vttool) under SunView (this might be fixed in later SunOS releases).
+
+   On the Sun with Open Windows, an additional symptom has been reported:
+   outbound SunLink X.25 connections "magically" translate CR typed at
+   the keyboard into LF before transmission to the remote host. This
+   doesn't happen under SunView.
+
+   SET CARRIER ON, when used on the SunOS 4.1 version of C-Kermit
+   (compiled in the BSD universe), causes the program to hang
+   uninterruptibly when SET LINE is issued for a device that is not
+   asserting carrier. When Kermit is built in the Sys V universe on the
+   same computer, there is no problem (it can be interrupted with
+   Ctrl-C). This is apparently a limitation of the BSD-style tty driver.
+
+   SunOS 4.1 C-Kermit has been observed to dump core when running a
+   complicated script program under cron. The dump invariably occurs in
+   ttoc(), while trying to output a character to a TCP/IP TELNET
+   connection. ttoc() contains a write() call, and when the system or the
+   network is very busy, the write() call can get stuck for long periods
+   of time. To break out of deadlocks caused by stuck write() calls,
+   there is an alarm around the write(). It is possible that the core
+   dump occurs when this alarm signal is caught. (This one has not been
+   observed recently -- possibly fixed in edit 190.)
+
+   On Sun computers with SunOS 4.0 or 4.1, SET FLOW RTS/CTS works only if
+   the carrier signal is present from the communication device at the
+   time when C-Kermit enters packet mode or CONNECT mode. If carrier is
+   not sensed (e.g. when dialing), C-Kermit does not attempt to turn on
+   RTS/CTS flow control. This is because the SunOS serial device driver
+   does not allow characters to be output if RTS/CTS is set (CRTSCTS) but
+   carrier (and DSR) are not present. Workaround (maybe): SET CARRIER OFF
+   before giving the SET LINE command, establish the connection, then SET
+   FLOW RTS/CTS
+
+   It has also been reported that RTS/CTS flow control under SunOS 4.1
+   through 4.1.3 works only on INPUT, not on output, and that there is a
+   patch from Sun to correct this problem: Patch-ID# T100513-04, 20 July
+   1993 (this patch might apply only to SunOS 4.1.3). It might also be
+   necessary to configure the eeprom parameters of the serial port; e.g.
+   do the following as root at the shell prompt:
+
+  eeprom  ttya-ignore-cd=false
+  eeprom  ttya-rts-dtr-off=true
+
+   There have been reports of file transfer failures on Sun-3 systems
+   when using long packets and/or large window sizes. One user says that
+   when this happens, the console issues many copies of this message:
+
+  chaos vmunix: zs1: ring buffer overflow
+
+   This means that SunOS is not scheduling Kermit frequently enough to
+   service interrupts from the zs serial device (Zilog 8350 SCC serial
+   communication port) before its input silo overflows. Workaround: use
+   smaller packets and/or a smaller window size, or use "nice" to
+   increase Kermit's priority. Use hardware flow control if available, or
+   remove other active processes before running Kermit.
+
+   SunLink X.25 support in C-Kermit 5A(190) was built and tested
+   successfully under SunOS 4.1.3b and SunLink X.25 7.00.
+    ________________________________________________________________________
+
+  3.9. C-KERMIT AND ULTRIX
+
+   [ [454]Top ] [ [455]Contents ] [ [456]Section Contents ] [ [457]Next ]
+   [ [458]Previous ]
+
+   See also: The [459]comp.unix.ultrix and [460]comp.sys.dec newsgroups.
+
+   There is no hardware flow control in Ultrix. That's not a Kermit
+   deficiency, but an Ultrix one.
+
+   When sending files to C-Kermit on a Telnet connection to a remote
+   Ultrix system, you must SET PREFIXING ALL (or at least prefix more
+   control characters than are selected by SET PREFIXING CAUTIOUS).
+
+   Reportedly, DEC ULTRIX 4.3 is immune to C-Kermit's disabling of
+   SIGQUIT, which is the signal that is generated when the user types
+   Ctrl-\, which kills the current process (i.e. C-Kermit) and dumps
+   core. Diagnosis and cure unknown. Workaround: before starting C-Kermit
+   -- or for that matter, when you first log in because this applies to
+   all processes, not just Kermit -- give the following Unix command:
+
+  stty quit undef
+
+   Certain operations driven by RS-232 modem signal do not work on
+   DECstations or other DEC platforms whose serial interfaces use MMP
+   connectors (DEC version of RJ45 telephone jack with offset tab). These
+   connectors convey only the DSR and DTR modem signals, but not carrier
+   (CD), RTS, CTS, or RI. Use SET CARRIER OFF to enable communication, or
+   "hotwire" DSR to CD.
+
+   The maximum serial speed on the DECstation 5000 is normally 19200, but
+   various tricks are available (outside Kermit) to enable higher rates.
+   For example, on the 5000/200, 19200 can be remapped (somehow,
+   something to do with "a bit in the SIR", whatever that is) to 38400,
+   but in software you must still refer to this speed as 19200; you can't
+   have 19200 and 38400 available at the same time.
+
+   19200, reportedly, is also the highest speed supported by Ultrix, but
+   NetBSD reportedly supports speeds up to 57600 on the DECstation,
+   although whether and how well this works is another question.
+
+   In any case, given the lack of hardware flow control in Ultrix, high
+   serial speeds are problematic at best.
+    ________________________________________________________________________
+
+  3.10. C-KERMIT AND UNIXWARE
+
+   [ [461]Top ] [ [462]Contents ] [ [463]Section Contents ] [ [464]Next ]
+   [ [465]Previous ]
+
+   See also:
+     * The Freebird Project (Unixware software repository)
+       [466]http://www.freebird.org/
+     * The UnixWare FAQ: [467]http://www.freebird.org/faq/
+     * The following newsgroups:
+          + [468]comp.unix.unixware.misc
+          + [469]comp.unix.sco.misc.
+
+   Also see general comments on PC-based Unixes in [470]Section 3.0. By
+   the way, this section is separate from the SCO (Caldera) section
+   because at the time this section was started, Unixware was owned by a
+   company called Univel. Later it was sold to Novell, and then to SCO.
+   Still later, SCO was sold to Caldera.
+
+   In Unixware 2.0 and later, the preferred serial device names (drivers)
+   are /dev/term/00 (etc), rather than /dev/tty00 (etc). Note the
+   following correspondence of device names and driver characteristics:
+
+  New name       Old name     Description              
+  /dev/term/00   /dev/tty00   ???
+  /dev/term/00h  /dev/tty00h  Modem signals and hardware flow control
+  /dev/term/00m  /dev/tty00m  Modem signals(?)
+  /dev/term/00s  /dev/tty00s  Modem signals and software flow control
+  /dev/term/00t  /dev/tty00t  ???
+
+   Lockfile names use device.major.minor numbers, e.g.:
+
+  /var/spool/locks/LK.7679.003.005
+
+   The minor number varies according to the device name suffix (none, h,
+   m, s, or t). Only the device and major number are compared, and thus
+   all of the different names for the same physical device (e.g. all of
+   those shown in the table above) interlock effectively.
+
+   Prior to UnixWare 7, serial speeds higher than 38400 are not
+   supported. In UnixWare 7, we also support 57600 and 115200, plus some
+   unexpected ones like 14400, 28800, and 76800, by virtue of a strange
+   new interface, evidently peculiar to UnixWare 7, discovered while
+   digging through the header files: tcsetspeed(). Access to this
+   interface is allowed only in POSIX builds, and thus the UnixWare 7
+   version of C-Kermit is POSIX-based, unlike C-Kermit for Unixware 1.x
+   and 2.x (since the earlier UnixWare versions did not support high
+   serial speeds, period).
+
+   HOWEVER, turning on POSIX features engages all of the "#if
+   (!_POSIX_SOURCE)" clauses in the UnixWare header files, which in turn
+   prevent us from having modem signals, access to the hardware flow
+   control APIs, select(), etc -- in short, all the other things we need
+   in communications software, especially when high speeds are used. Oh
+   the irony. And so C-Kermit must be shamelessly butchered -- as it has
+   been so many times before -- to allow us to have the needed features
+   from the POSIX and non-POSIX worlds. See the UNIXWAREPOSIX sections of
+   [471]ckutio.c.
+
+   After the butchery, we wind up with Unixware 2.x having full
+   modem-signal capability, but politically-correct Unixware 7.x lacking
+   the ability to automatically detect a broken connection when carrier
+   drops.
+
+   Meanwhile the Unixware tcsetspeed() function allows any number at all
+   (any long, 0 or positive) as an argument and succeeds if the number is
+   a legal bit rate for the serial device, and fails otherwise. There is
+   no list anywhere of legal speeds. Thus the SET SPEED keyword table
+   ("set speed ?" to see it) is hardwired based on trial and error with
+   all known serial speeds, the maximum being 115200. However, to allow
+   for the possibility that other speeds might be allowed in the future
+   (or with different port drivers), the SET SPEED command for UnixWare 7
+   only allows you to specify any number at all; a warning is printed if
+   the number is not in the list, but the number is accepted anyway; the
+   command succeeds if tcsetspeed() accepts the number, and fails
+   otherwise.
+
+   In C-Kermit 8.0 testing, it was noticed that the POSIX method for
+   hanging up the phone by dropping DTR (set speed 0, pause, restore
+   speed) did not actually drop DTR. The APIs do not return any error
+   indication, but nothing happens. I changed tthang() to skip the
+   special case I had made for Unixware and instead follow the normal
+   path: if TIOCSDTR is defined use that, otherwise blah blah... It turns
+   out TIOCSDTR *is* defined, and it works.
+
+   So in Unixware (at least in 2.1.3) we can read modem signals, hangup
+   by toggling DTR, and so on, BUT... But once the remote hangs up and
+   Carrier drops, the API for reading modem signals ceases to function;
+   although the device is still open, the TIOCMGET ioctl always raises
+   errno 6 = ENXIO, "No such device or address".
+
+   Old business:
+
+   Using C-Kermit 6.0 on the UnixWare 1.1 Application Server, one user
+   reported a system panic when the following script program is executed:
+
+  set line /dev/tty4
+  set speed 9600
+  output \13
+  connect
+
+   The panic does not happen if a PAUSE is inserted:
+
+  set line /dev/tty4
+  set speed 9600
+  pause 1
+  output \13
+  connect
+
+   This is using a Stallion EasyIO card installed as board 0 on IRQ 12 on
+   a Gateway 386 with the Stallion-supplied driver. The problem was
+   reported to Novell and Stallion and (reportedly) is now fixed.
+    ________________________________________________________________________
+
+  3.11. C-KERMIT AND APOLLO SR10
+
+   [ [472]Top ] [ [473]Contents ] [ [474]Section Contents ] [ [475]Next ]
+   [ [476]Previous ]
+
+   Reportedly, version 5A(190), when built under Apollo SR10 using "make
+   sr10-bsd", compiles, links, and executes OK, but leaves the terminal
+   unusable after it exits -- the "cs7" or "cs8" (character size)
+   parameter has become cs5. The terminal must be reset from another
+   terminal. Cause and cure unknown. Suggested workaround: Wrap Kermit in
+   a shell script something like:
+
+  kermit @*
+  stty sane
+    ________________________________________________________________________
+
+  3.12. C-KERMIT AND TANDY XENIX 3.0
+
+   [ [477]Top ] [ [478]Contents ] [ [479]Section Contents ] [ [480]Next ]
+   [ [481]Previous ]
+
+   C-Kermit 7.0 was too big to be built on Tandy Xenix, even in a minimum
+   configuration; version 6.0 is the last one that fits.
+
+   Reportedly, in C-Kermit 6.0, if you type lots of Ctrl-C's during
+   execution of the initialization file, ghost Kermit processes will be
+   created, and will compete for the keyboard. They can only be removed
+   via "kill -9" from another terminal, or by rebooting. Diagnosis --
+   something strange happening with the SIGINT handler while the process
+   is reading the directory (it seems to occur during the SET PROMPT
+   [\v(dir)] ... sequence). Cure: unknown. Workaround: don't interrupt
+   C-Kermit while it is executing its init file on the Tandy 16/6000.
+    ________________________________________________________________________
+
+  3.13. C-KERMIT AND OSF/1 (DIGITAL UNIX) (TRU64 UNIX)
+
+   [ [482]Top ] [ [483]Contents ] [ [484]Section Contents ] [ [485]Next ]
+   [ [486]Previous ]
+
+   While putting together and testing C-Kermit 8.0, it was discovered
+   that binaries built for one version of Tru64 Unix (e.g. 4.0G) might
+   exhibit very strange behavior if run on a different version of Tru64
+   Unix (e.g. 5.1A). The typical symptom was that a section of the
+   initialization file would be skipped, notably locating the dialing
+   and/or network directory as well as finding and executing the
+   customization file, ~/.mykermrc. This problem also is reported to
+   occur on Tru64 Unix 5.0 (Rev 732) even when running a C-Kermit binary
+   that was built there. However, the Tru64 5.1A binary works correctly
+   on 5.0. Go figure.
+
+   When making Telnet connections to a Digital Unix or Tru64 system, and
+   your Telnet client forwards your user name, the Telnet server
+   evidently stuffs the username into login's standard input, and you
+   see:
+
+  login: ivan
+  Password:
+
+   This is clearly going to play havoc with scripts that look for
+   "login:". Workaround (when Kermit is your Telnet client): SET LOGIN
+   USER to nothing, to prevent Kermit from sending your user ID.
+
+   Before you can use a serial port on a new Digital Unix system, you
+   must run uucpsetup to enable or configure the port. Evidently the
+   /dev/tty00 and 01 devices that appear in the configuration are not
+   usable; uucpsetup turns them into /dev/ttyd00 and 01, which are. Note
+   that uucpsetup and other uucp-family programs are quite primitive --
+   they only know about speeds up to 9600 bps and their selection of
+   modems dates from the early 1980s. None of this affects Kermit, though
+   -- with C-Kermit, you can use speeds up to 115200 bps (at least in
+   DU4.0 and later) and modern modems with hardware flow control and all
+   the rest.
+
+   Reportedly, if a modem is set for &S0 (assert DSR at all times), the
+   system resets or drops DTR every 30 seconds; reportedly DEC says to
+   set &S1.
+
+   Digital Unix 3.2 evidently wants to believe your terminal is one line
+   longer than you say it is, e.g. when a "more" or "man" command is
+   given. This is has nothing to do with C-Kermit, but tends to annoy
+   those who use Kermit or other terminal emulators to access Digital
+   Unix systems. Workaround: tell Unix to "stty rows 23" (or whatever).
+
+   Reportedly, there is some bizarre behavior when trying to use a
+   version of C-Kermit built on one Digital Unix 4.0 system on another
+   one, possibly due to differing OS or library revision levels; for
+   example, the inability to connect to certain TCP/IP hosts. Solution:
+   rebuild C-Kermit from source code on the system where you will be
+   using it.
+
+   Digital Unix tgetstr() causes a segmentation fault. C-Kermit 7.0 added
+   #ifdefs to avoid calling this routine in Digital Unix. As a result,
+   the SCREEN commands always send ANSI escape sequences -- even though
+   curses knows your actual terminal type.
+
+   Reportedy the Tru64 Unix 4.0E 1091 Telnet server does not tolerate
+   streaming transfers into itself, at least not when the sending Kermit
+   is on the same local network. Solution: tell one Kermit or the other
+   (or both) to "set streaming off". This might or might be the case with
+   earlier and/or later Tru64, Digital Unix, and OSF/1 releases.
+    ________________________________________________________________________
+
+  3.14. C-KERMIT AND SGI IRIX
+
+   [ [487]Top ] [ [488]Contents ] [ [489]Section Contents ] [ [490]Next ]
+   [ [491]Previous ]
+
+   See also:
+     * The [492]comp.sys.sgi.misc and [493]comp.sys.sgi.admin newsgroups.
+       [494]The SGI website
+     * The SGI FAQ:
+          + [495]http://www-viz.tamu.edu/~sgi-faq/
+          + [496]ftp://viz.tamu.edu/pub/sgi/faq/
+
+   About IRIX version numbers: "uname -a" tells the "two-digit" version
+   number, such as "5.3" or "6.5". The three-digit form can be seen with
+   "uname -R". (this information is unavailable at the simple API level).
+   Supposedly all three-digit versions within the same two-digit version
+   (e.g. 6.5.2, 6.5.3) are binary compatible; i.e. a binary built on any
+   one of them should run on all others. The "m" suffix denotes just
+   patches; the "f" suffix indicates that features were added.
+
+   An IRIX binary built on lower MIPS model (Instruction Set
+   Architecture, ISA) can run on higher models, but not vice versa:
+
+     MIPS1 R3000 and below
+     MIPS2 R4000
+     MIPS3 R4x00
+     MIPS4 R5000 and above
+
+   Furthermore, there are different Application Binary Inferfaces (ABIs):
+
+     COFF    32 bits, IRIX 5.3, 5.2, 5.1, 4.x and below
+     o32 ELF 32 bits, IRIX 5.3, 6.0 - 6.5
+     N32 ELF 32 bits, IRIX 6.2 - 6.5
+     N64 ELF 64 bits, IRIX 6.2 - 6.5
+
+   Thus a prebuilt IRIX binary works on a particular machine only if (a)
+   the machine's IRIX version (to one decimal place) is equal to or
+   greater than the version under which the binary was built; (b) the
+   machine's MIPS level is greater or equal to that of the binary; and
+   (c) the machine supports the ABI of the binary. If all three
+   conditions are not satisfied, of course, you can build a binary
+   yourself from source code since, unlike some other Unix vendors, SGI
+   does supply a C compiler and libraries.
+
+   SGI did not supply an API for hardware flow control prior to IRIX 5.2.
+   C-Kermit 6.1 and higher for IRIX 5.2 and higher supports hardware flow
+   control in the normal way, via "set flow rts/cts".
+
+   For hardware flow control on earlier IRIX and/or C-Kermit versions,
+   use the ttyf* (modem control AND hardware flow control) devices and
+   not the ttyd* (direct) or ttym* (modem control but no hardware flow
+   control) ones, and obtain the proper "hardware handshaking" cable from
+   SGI, which is incompatible with the ones for the Macintosh and NeXT
+   even though they look the same ("man serial" for further info) and
+   tell Kermit to "set flow keep" and "set modem flow rts/cts".
+
+   Serial speeds higher than 38400 are available in IRIX 6.2 and later,
+   on O-class machines (e.g. Origin, Octane) only, and are supported by
+   C-Kermit 7.0 and later. Commands such as "set speed 115200" may be
+   given on other models (e.g. Iris, Indy, Indigo) but will fail because
+   the OS reports an invalid speed for the device.
+
+   Experimentation with both IRIX 5.3 and 6.2 shows that when logged in
+   to IRIX via Telnet, that remote-mode C-Kermit can't send files if the
+   packet length is greater than 4096; the Telnet server evidently has
+   this restriction (or bug), since there is no problem sending long
+   packets on serial or rlogin connections. However, it can receive files
+   with no problem if the packet length is greater than 4096. As a
+   workaround, the FAST macro for IRIX includes "set send packet-length
+   4000". IRIX 6.5.1 does not have this problem, so evidently it was
+   fixed some time after IRIX 6.2. Tests show file-transfer speeds are
+   better (not worse) with 8K packets than with 4K packets from IRIX
+   6.5.1.
+
+   Reportedly some Indys have bad serial port hardware. IRIX 5.2, for
+   example, needs patch 151 to work around this; or upgrade to a later
+   release. Similarly, IRIX 5.2 has several problems with serial i/o,
+   flow control, etc. Again, patch or upgrade.
+
+   Reportedly on machines with IRIX 4.0, Kermit cannot be suspended by
+   typing the suspend ("swtch") character if it was started from csh,
+   even though other programs can be suspended this way, and even though
+   the Z and SUSPEND commands still work correctly. This is evidently
+   because IRIX's csh does not deliver the SIGTSTP signal to Kermit. The
+   reason other programs can be suspended in the same environment is
+   probably that they do not trap SIGTSTP themselves, so the shell is
+   doing the suspending rather than the application.
+
+   Also see notes about IRIX 3.x in the [497]C-Kermit for Unix
+   Installation Instructions.
+
+   If you have problems making TCP/IP connections in versions of IRIX
+   built with GCC 2.95.2, see the bugs section of:
+
+  [498]http://freeware.sgi.com/Installable/gcc-2.95.2.html.
+
+   Reportedly, if you allow gcc to compile C-Kermit on Irix you should be
+   aware that there might be problems with some of the network code. The
+   specifics are at
+   [499]http://freeware.sgi.com/Installable/gcc-2.95.2.html; scroll down
+   to the "known bugs" section at the end of the document.
+    ________________________________________________________________________
+
+  3.15. C-KERMIT AND THE BEBOX
+
+   [ [500]Top ] [ [501]Contents ] [ [502]Section Contents ] [ [503]Next ]
+   [ [504]Previous ]
+
+   See also: The [505]comp.sys.be newsgroup.
+
+   The BeBox has been discontinued and BeOS repositioned for PC
+   platforms. The POSIX parts of BeOS are not finished, nor is the
+   sockets library, therefore a fully functional version of C-Kermit is
+   not possible. In version 6.0 of C-Kermit, written for BeOS DR7, it was
+   possible to:
+
+     * set line /dev/serial2 (and probably the other serial ports)
+     * set speed 115200 (and at least some of the lower baud rates)
+     * connect
+     * set modem type hayes (and likely others, too)
+     * dial phone-number
+     * set send packet-length 2048 (other lengths for both send and
+       receive)
+     * set receive packet length 2048
+     * set file type binary (text mode works, too) (with remote kermit
+       session in server mode)
+     * put bedrop.jpg
+     * get bedrop.jpg
+     * get bedrop.jpg bedrop.jpg2
+     * finish, bye
+
+   The following do not work:
+     * kermit does not detect modem hangup
+     * !/RUN/PUSH [commandline command]
+     * Running kermit in remote mode
+     * Using other protocols (x/y/zmodem)
+     * TCP networking interface (Be's TCP/IP API has a ways to go, still)
+
+   C-Kermit does not work on BeOS DR8 because of changes in the
+   underlying APIs. Unfortunately not enough changes were made to allow
+   the regular POSIX-based C-Kermit to work either. Note: the lack of a
+   fork() service requires the select()-based CONNECT module, but there
+   is no select(). There is a select() in DR8, but it doesn't work.
+
+   C-Kermit 7.0 was built for BeOS 4.5 and works in remote mode. It does
+   not include networking support since the APIs are still not there. It
+   is not known if dialing out works, but probably not. Be experts are
+   welcome to lend a hand.
+    ________________________________________________________________________
+
+  3.16. C-KERMIT AND DG/UX
+
+   [ [506]Top ] [ [507]Contents ] [ [508]Section Contents ] [ [509]Next ]
+   [ [510]Previous ]
+
+   Somebody downloaded the C-Kermit 6.0 binary built under DG/UX 5.40 and
+   ran it under DG/UX 5.4R3.10 -- it worked OK except that file dates for
+   incoming files were all written as 1 Jan 1970. Cause and cure unknown.
+   Workaround: SET ATTRIBUTE DATE OFF. Better: Use a version of C-Kermit
+   built under and for DG/UX 5.4R3.10.
+    ________________________________________________________________________
+
+  3.17. C-KERMIT AND SEQUENT DYNIX
+
+   [ [511]Top ] [ [512]Contents ] [ [513]Section Contents ] [ [514]Next ]
+   [ [515]Previous ]
+
+   Reportedly, when coming into a Sequent Unix (DYNIX) system through an
+   X.25 connection, Kermit doesn't work right because the Sequent's
+   FIONREAD ioctl returns incorrect data. To work around, use the
+   1-character-at-a-time version of myread() in ckutio.c (i.e. undefine
+   MYREAD in ckutio.c and rebuild the program). This is unsatisfying
+   because two versions of the program would be needed -- one for use
+   over X.25, and the other for serial and TCP/IP connections.
+    ________________________________________________________________________
+
+  3.18. C-KERMIT AND {FREE,OPEN,NET}BSD
+
+   [ [516]Top ] [ [517]Contents ] [ [518]Section Contents ] [ [519]Next ]
+   [ [520]Previous ]
+
+   Some NebBSD users have reported difficulty escaping back from CONNECT
+   mode, usually when running NetBSD on non-PC hardware. Probably a
+   keyboard issue.
+
+   NetBSD users have also reported that C-Kermit doesn't pop back to the
+   prompt if the modem drops carrier. This needs to be checked out &
+   fixed if possible.
+
+   (All the above seems to work properly in C-Kermit 7.0 and later.)
+    ________________________________________________________________________
+
+  3.19. C-KERMIT AND MAC OS X (Rhapsody, Darwin, Jaguar, Panther)
+
+   [ [521]Top ] [ [522]Contents ] [ [523]Section Contents ] [ [524]Next ]
+   [ [525]Previous ]
+
+   Mac OS X is Apple's 4.4BSD Unix variety, closely related to FreeBSD,
+   but different. "uname -a" is singularly uninformative, as in Linux,
+   giving only the Darwin kernel version number. As far as I can tell,
+   there is no way to find out the Mac OS X version number, such as 10.3
+   (in Linux you can find the distribution version in a
+   distribution-dependent file). Here are some points to be aware of:
+
+     * The biggest gotcha for Kermit users is that Mac OS X does not
+       support serial ports and, as far as I can tell, doesn't support
+       its built-in modem either, for anything other than making Internet
+       connections. Macintoshes capable of running Mac OS X, such as the
+       G5, some without serial ports and without any APIs to support
+       them, and also without the UUCP family of programs (including cu),
+       nor any standard for serial-port lockfile directory.
+     * At least early versions of Mac OS X came without Curses, Termlib,
+       or Terminfo libraries. Later versions seem to have ncurses. Kermit
+       uses curses for its file-transfer display. See elsewhere about
+       curses-vs-ncurses confusion.
+     * In the HFS+ file system, filenames are case-folded. Thus
+       "makefile" and "Makefile" are the same file. The UFS file system
+       is, like normal Unix, case-sensitive.
+     * Files that are composed of a resource fork and a data fork... I
+       doubt that C-Kermit does anything useful with them. There is no
+       code in C-Kermit for traditional two-forked Macintosh files, but
+       it could be added if there is any demand.
+     * In case you want to transfer a traditional Macintosh text file (or
+       data fork of a file that is plain text), you can use these
+       C-Kermit commands:
+
+set file eol cr
+set file character-set apple-quickdraw
+send /text filename
+
+     * File or pathnames that include spaces must be enclosed in either
+       doublequotes or curly braces in C-Kermit commands.
+     * Mac OS X has its own package format for applications, called
+       "fink". Various fink packages for C-Kermit are floating around
+       that are not standard releases. For example, there's a C-Kermit
+       8.0.201 package in which C-Kermit was modifed (at least) to use a
+       UUCP lockfile directory that does not exist on vanilla Mac OS X
+       systems.
+
+    Mac OS X and Serial Ports
+
+   Apple is in the forefront of companies that believe serial ports have
+   no use in the modern world and so has simply eliminated all traces of
+   them from its machines and OS. But of course serial ports are still
+   needed to connect not only to external modems, but also to the control
+   ports of hubs, routers, terminal servers, PBXs, and similar devices,
+   not to mention barcode readers, POS systems and components, automated
+   factory-floor equipment, and scientific, medical, and lab equipment
+   (to name a few). Among workers in these areas, there is a need to add
+   serial ports back onto this platform, which is being filled by
+   third-party products such as the [526]Keyspan USB Serial Adapter. To
+   use the Keyspan device, you must install the accompanying device
+   drivers, which wind up giving you serial ports with names like
+   /dev/cu.USA19H3b1P1.1.
+
+   To configure your Mac OS X system to allow C-Kermit to use these (or
+   any other) serial devices:
+
+    1. su
+       chgrp xxxx /var/spool/lock
+       chmod g+w /var/spool/lock
+       chgrp xxxx /dev/cu.*
+       (where xxxx is the name of the group for users to whom serial-port
+       access is to be granted). Use "admin" or other existing group, or
+       create a new group if desired. NB:
+
+     In the absence of official guidance from Apple or anyone else, we
+     choose /var/spool/lock as the lockfile directory because this
+     directory (a) already exists on vanilla Mac OS X installations, and
+     (b) it is the directory used for serial-port lockfiles on many
+     other platforms. 
+    2. Put all users who need access to the serial port in the same
+       group.
+    3. Make sure the serial device files that are to be used by C-Kermit
+       have group read-write permission and (if you care) lack world
+       read-write permission, e.g.:
+       chmod g+rw,o-rw /dev/cu.*
+
+   If you do the above, then there's no need to become root to use
+   Kermit, or to make Kermit suid or sgid. Just do this:
+
+chmod 775 wermit
+mv wermit /usr/local/bin/kermit
+
+   (or whatever spot is more appropriate). For greater detail about
+   installation (man page, etc), [527]CLICK HERE.
+
+   Back when Macs had serial ports, they were not RS-232 (the standard
+   for connecting computers with nearby modems) but rather RS-422 or -423
+   (a standard for connecting serial devices over longer distances).
+   Macintosh serial ports do not support modems well because they do not
+   have enough wires (or more properly in the case RS-422/423, wire
+   pairs) to convey a useful subset of modem signals. The Keyspan USB
+   adapter gives you two Mini-Din8 RS-422 ports, that are no better (or
+   worse) for communicating with modems or serial devices than a real Mac
+   Din-8 port was. In essense, you get Data In, Data Out, and two modem
+   signals. It looks to me as if the signals chosen by Keyspan are RTS
+   and CTS. This gives you hardware flow control, but at the expense of
+   Carrier Detect. Thus to use C-Kermit with a Keyspan USB serial port,
+   you must tell C-Kermit to:
+
+set modem type none                ; (don't expect a modem)
+set carrier-watch off              ; (ignore carrier signal)
+set port /dev/cu.USA19H3b1P1.1     ; (open the port)
+set flow rts/cts                   ; (this is the default)
+set speed 57600                    ; (or whatever)
+connect                            ; (or whatever)
+
+   Use Ctrl-\C in the normal manner to escape back to the C-Kermit>
+   prompt. Kermit can't pop back to its prompt automatically when Carrier
+   drops because there is no Carrier signal.
+
+         Instructions for the built-in modem remain to be written.
+
+   Links:
+     * [528]Unix tips for Mac OS X (Jerry Stratton)
+    ________________________________________________________________________
+
+  3.20. C-KERMIT AND COHERENT
+
+   [ [529]Top ] [ [530]Contents ] [ [531]Section Contents ] [
+   [532]Previous ]
+
+   Also see:
+
+     [533]http://www.uni-giessen.de/faq/archiv/coherent-faq.general/msg00
+   000.html
+
+   Mark Williams COHERENT was perhaps the first commercial Unix-based
+   operating system for PCs, first appearing about 1983 or -84 for the
+   PC/XT (?), and popular until about 1993, when Linux took over.
+   C-Kermit, as of version 8.0, is still current for COHERENT 386 4.2
+   (i.e. only for i386 and above). Curses is included, but lots of other
+   features are omitted due to lack of the appropriate OS features, APIs,
+   libraries, hardware, or just space: e.g. TCP/IP, floating-point
+   arithmetic, learned scripts. Earlier versions of COHERENT ran on 8086
+   and 80286, but these are to small to build or run C-Kermit, but
+   G-Kermit should be OK (as might be ancient versions of C-Kermit).
+
+   You can actually build a version with floating point support -- just
+   take -DNOFLOAT out of CFLAGS and add -lm to LIBS; NOFLOAT is the
+   default because COHERENT tends to run on old PCs that don't have
+   floating-point hardware. You can also add "-f" to CFLAGS to have it
+   link in the floating-point emulation library. Also I'm not sure why
+   -DNOLEARN is included, since it depends on select(), which COHERENT
+   has.
+    ________________________________________________________________________
+
+  4. GENERAL UNIX-SPECIFIC HINTS, LIMITATIONS, AND BUGS
+
+   [ [534]Top ] [ [535]Contents ] [ [536]Next ] [ [537]Previous ]
+
+  4.1. Modem Signals
+
+   There seems to be an escalating demand for the ability to control
+   "dumb serial devices" (such as "smartcard readers", barcode readers,
+   etc) by explicitly manipulating modem signals, particularly RTS. This
+   might have been easy to do in DOS, where there is no operating system
+   standing between the application and the serial device, but it is
+   problematic in Unix, where modem signals are controlled by the serial
+   device driver. If the driver does not provide an API for doing this,
+   then the application can't do it. If it does provide an API, expect it
+   to be totally different on each Unix platform, since there is no
+   standard for this.
+
+  4.2. NFS Troubles
+
+   Beginning with C-Kermit 6.0, the default C-Kermit prompt includes your
+   current (working) directory; for example:
+
+  [/usr/olga] C-Kermit>
+
+   (In C-Kermit 7.0 the square braces were replaced by round parentheses
+   to avoid conflicts with ISO 646 national character sets.)
+
+   If that directory is on an NFS-mounted disk, and NFS stops working or
+   the disk becomes unavailable, C-Kermit will hang waiting for NFS
+   and/or the disk to come back. Whether you can interrupt C-Kermit when
+   it is hung this way depends on the specific OS. Kermit has called the
+   operating systems's getcwd() function, and is waiting for it to
+   return. Some versions of Unix (e.g. HP-UX 9.x) allow this function to
+   be interrupted with SIGINT (Ctrl-C), others (such as HP-UX 8.x) do
+   not. To avoid this effect, you can always use SET PROMPT to change
+   your prompt to something that does not involve calling getcwd(), but
+   if NFS is not responding, C-Kermit will still hang any time you give a
+   command that refers to an NFS-mounted directory. Also note that in
+   some cases, the uninterruptibility of NFS-dependent system or library
+   calls is considered a bug, and sometimes there are patches. For HP-UX,
+   for example:
+
+                                                        replaced by:
+  HP-UX 10.20     libc    PHCO_8764                     PHCO_14891/PHCO_16723
+  HP-UX 10.10     libc    PHCO_8763                     PHCO_14254/PHCO_16722
+  HP-UX 9.x       libc    PHCO_7747       S700          PHCO_13095
+  HP-UX 9.x       libc    PHCO_6779       S800          PHCO_11162
+
+  4.3. C-Kermit as Login Shell
+
+   You might have reason to make C-Kermit the login shell for a specific
+   user, by entering the pathname of Kermit (possibly with command-line
+   switches, such as -x to put it in server mode) into the shell field of
+   the /etc/passwd file. This works pretty well. In some cases, for
+   "ultimate security", you might want to use a version built with
+   -DNOPUSH (see the [538]Configurations Options document for this, but
+   even if you don't, then PUSHing or shelling out from C-Kermit just
+   brings up a new copy of C-Kermit (but warning: this does not prevent
+   the user from explicitly running a shell; e.g. "run /bin/sh"; use
+   NOPUSH to prevent this).
+
+  4.4. C-Kermit versus screen and splitvt
+
+   C-Kermit file transfers will probably not work if attemped through the
+   "splitvt" or GNU "screen" programs because the screen optimization (or
+   at least, line wrapping, control-character absorption) done by this
+   package interferes with Kermit's packets.
+
+   The same can apply to any other environment in which the user's
+   session is captured, monitored, recorded, or manipulated. Examples
+   include the 'script' program (for making a typescript of a session),
+   the Computronics PEEK package and pksh (at least versions of it prior
+   to 1.9K), and so on.
+
+   You might try the following -- what we call "doomsday Kermit" --
+   settings to push packets through even the densest and most obstructive
+   connections, such as "screen" and "splitvt" (and certain kinds of 3270
+   protocol emulators): Give these commands to BOTH Kermit programs:
+
+  SET FLOW NONE
+  SET CONTROL PREFIX ALL
+  SET RECEIVE PACKET-LENGTH 70
+  SET RECEIVE START 62
+  SET SEND START 62
+  SET SEND PAUSE 100
+  SET BLOCK B
+
+   If it works, it will be slow.
+
+  4.5. C-Kermit versus DOS Emulators
+
+   On Unix workstations equipped with DOS emulators like SoftPC, watch
+   out for what these emulators do to the serial port drivers. After
+   using a DOS emulator, particularly if you use it to run DOS
+   communications software, you might have to reconfigure the serial
+   ports for use by Unix.
+
+  4.6. C-Kermit versus Job Control
+
+   Interruption by Ctrl-Z makes Unix C-Kermit try to suspend itself with
+   kill(0,SIGTSTP), but only on platforms that support job control, as
+   determined by whether the symbol SIGTSTP is defined (or on POSIX or
+   SVR4 systems, if syconf(_SC_JOB_CONTROL) or _POSIX_JOB_CONTROL in
+   addition to SIGTSTP). However, if Kermit is running under a login
+   shell (such as the original Bourne shell) that does not support job
+   control, the user's session hangs and must be logged out from another
+   terminal, or hung up on. There is no way Kermit can defend itself
+   against this. If you use a non-job control shell on a computer that
+   supports job control, give a command like "stty susp undef" to fix it
+   so the suspend signal is not attached to any particular key, or give
+   the command SET SUSPEND OFF to C-Kermit, or build C-Kermit with
+   -DNOJC.
+
+  4.7. Dates and Times
+
+   Unix time conversion functions typically apply locale rules to return
+   local time in terms of any seasonal time zone change in effect for the
+   given date. The diffdate function assumes that the same timezone rules
+   are in effect for both dates, but a date with timezone information
+   will be converted to the local time zone in effect at the given time,
+   e.g., a GMT specification will produce either a Standard Time or
+   Daylight Savings Time, depending on which applies at the given time.
+   An example using the 2001 seasonal change from EDT (-0400) to EST
+   (-0500):
+
+  C-Kermit> DATE 20011028 05:01:02 GMT  ; EDT
+  20011028 01:01:02
+  C-Kermit> DATE 20011028 06:01:02 GMT  ; EST
+  20011028 01:01:02
+  C-Kermit>
+
+   but the implicit change in timezone offset is not recognized:
+
+  C-Kermit> echo \fdiffdate(20011028 05:01:02 GMT, 20011028 06:01:02 GMT)
+  +0:00
+  C-Kermit>
+
+   Date/time arithmetic, offsets, delta times, and timezone support are
+   new to C-Kermit 8.0, and might be expected to evolve and improve in
+   subsequent releases.
+
+   On some platforms, files downloaded with HTTP receive the current
+   timestamp, rather than the HTTP "Last Modified" time (this can be
+   fixed by including utime.h, e.g. in SunOS and Tru64...).
+
+  4.8. Pseudoterminals
+
+   The SSH and PTY commands work by assigning a pseudoterminal and
+   reading and writing from it. Performance varies according to the
+   specific platform ranging from very fast to very flow.
+
+   SSH and PTY commands can fail if (a) all pseudoterminals are in use;
+   or (b) you do not have read/write access to the pseudoterminal that
+   was assigned. An example of (b) was reported with the Zipslack
+   Slackware Linux distribution, in which the pseudoterminals were
+   created with crw-r--r-- permission, instead of crw-rw-rw-.
+
+  4.9. Miscellaneous
+
+     * Reportedly, the Unix C-Kermit server, under some conditions, on
+       certain particular systems, fails to log out its login session
+       upon receipt of a BYE command. Before relying on the BYE command
+       working, test it a few times to make sure it works on your system:
+       there might be system configuration or security mechanisms to
+       prevent an inferior process (like Kermit) from killing a superior
+       one (like the login shell).
+     * On AT&T 7300 (3B1) machines, you might have to "stty nl1" before
+       starting C-Kermit. Do this if characters are lost during
+       communications operations.
+     * Under the bash shell (versions prior to 1.07 from CWRU), "pushing"
+       to an inferior shell and then exiting back to Kermit leaves Kermit
+       in the background such that it must be explicitly fg'd. This is
+       reportedly fixed in version 1.07 of bash (and definitely in modern
+       bash versions).
+    ________________________________________________________________________
+
+  5. INITIALIZATION AND COMMAND FILES
+
+   [ [539]Top ] [ [540]Contents ] [ [541]Next ] [ [542]Previous ]
+
+   C-Kermit's initialization file for Unix is .kermrc (lowercase, starts
+   with period) in your home directory, unless Kermit was built with the
+   system-wide initialization-file option (see the [543]C-Kermit for Unix
+   Installation Instructions).
+
+   C-Kermit identifies your home directory based on the environment
+   variable, HOME. Most Unix systems set this variable automatically when
+   you log in. If C-Kermit can't find your initialization file, check
+   your HOME variable:
+
+  echo $HOME      (at the Unix prompt)
+
+   or:
+
+  echo \$(HOME)   (at the C-Kermit prompt)
+
+   If HOME is not defined, or is defined incorrectly, add the appropriate
+   definition to your Unix .profile or .login file, depending on your
+   shell:
+
+  setenv HOME full-pathname-of-your-home-directory  (C-Shell, .login file)
+
+   or:
+
+  HOME=full-pathname-of-your-home-directory         (sh, ksh, .profile file)
+  export HOME
+
+   NOTE: Various other operations depend on the correct definition of
+   HOME. These include the "tilde-expansion" feature, which allows you to
+   refer to your home directory as "~" in filenames used in C-Kermit
+   commands, e.g.:
+
+  send ~/.kermrc
+
+   as well as the \v(home) variable.
+
+   Prior to version 5A(190), C-Kermit would look for its initialization
+   file in the current directory if it was not found in the home
+   directory. This feature was removed from 5A(190) because it was a
+   security risk. Some people, however, liked this behavior and had
+   .kermrc files in all their directories that would set up things
+   appropriately for the files therein. If you want this behavior, you
+   can accomplish it in various ways, for example:
+
+     * Create a shell alias, for example:
+  alias kd="kermit -Y ./.kermrc"
+     * Create a .kermrc file in your home directory, whose contents are:
+  take ./.kermrc
+
+   Suppose you need to pass a password from the Unix command line to a
+   C-Kermit script program, in such a way that it does not show up in
+   "ps" or "w" listings. Here is a method (not guaranteed to be 100%
+   secure, but definitely more secure than the more obvious methods):
+
+  echo mypassword | kermit myscript
+
+   The "myscript" file contains all the commands that need to be executed
+   during the Kermit session, up to and including EXIT, and also includes
+   an ASK or ASKQ command to read the password from standard input, which
+   has been piped in from the Unix 'echo' command, but it must not
+   include a CONNECT command. Only "kermit myscript" shows up in the ps
+   listing.
+    ________________________________________________________________________
+
+  6. COMMUNICATION SPEED SELECTION
+
+   [ [544]Top ] [ [545]Contents ] [ [546]Next ] [ [547]Previous ]
+
+   Version-7 based Unix implementations, including 4.3 BSD and earlier
+   and Unix systems based upon BSD, use a 4-bit field to record a serial
+   device's terminal speed. This leaves room for 16 speeds, of which the
+   first 14 are normally:
+
+     0, 50, 75, 110, 134.5, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+     and 9600
+
+   The remaining two are usually called EXTA and EXTB, and are defined by
+   the particular Unix implementation. C-Kermit determines which speeds
+   are available on your system based on whether symbols for them are
+   defined in your terminal device header files. EXTA is generally
+   assumed to be 19200 and EXTB 38400, but these assumptions might be
+   wrong, or they might not apply to a particular device that does not
+   support these speeds. Presumably, if you try to set a speed that is
+   not legal on a particular device, the driver will return an error, but
+   this can not be guaranteed.
+
+   On these systems, it is usually not possible to select a speed of
+   14400 bps for use with V.32bis modems. In that case, use 19200 or
+   38400 bps, configure your modem to lock its interface speed and to use
+   RTS/CTS flow control, and tell C-Kermit to SET FLOW RTS/CTS and SET
+   DIAL SPEED-MATCHING OFF.
+
+   The situation is similar, but different, in System V. SVID Third
+   Edition lists the same speeds, 0 through 38400.
+
+   Some versions of Unix, and/or terminal device drivers that come with
+   certain third-party add-in high-speed serial communication interfaces,
+   use the low "baud rates" to stand for higher ones. For example, SET
+   SPEED 50 gets you 57600 bps; SET SPEED 75 gets you 76800; SET SPEED
+   110 gets 115200.
+
+   SCO ODT 3.0 is an example where a "baud-rate-table patch" can be
+   applied that can rotate the tty driver baud rate table such that
+   600=57600 and 1800=115k baud. Similarly for Digiboard
+   multiport/portservers, which have a "fastbaud" setting that does this.
+   Linux has a "setserial" command that can do it, etc.
+
+   More modern Unixes support POSIX-based speed setting, in which the
+   selection of speeds is not limited by a 4-bit field. C-Kermit 6.1
+   incorporates a new mechanism for finding out (at compile time) which
+   serial speeds are supported by the operating system that does not
+   involve editing of source code by hand; on systems like Solaris 5.1,
+   IRIX 6.2, and SCO OSR5.0.4, "set speed ?" will list speeds up to
+   460800 or 921600. In C-Kermit 7.0 and later:
+
+    1. If a symbol for a particular speed (say B230400 for 230400 bps)
+       appears in whatever header file defines acceptable serial speeds
+       (e.g. <termbits.h> or <sys/termios.h> or <sys/ttydev.h>, etc), the
+       corresponding speed will appear in C-Kermit's "set speed ?" list.
+    2. The fact that a given speed is listed in the header files and
+       appears in C-Kermit's list does not mean the driver will accept
+       it. For example, a computer might have some standard serial ports
+       plus some add-on ones with different drivers that accept a
+       different repertoire of speeds.
+    3. The fact that a given speed is accepted by the driver does not
+       guarantee the underlying hardware can accept it.
+
+   When Kermit is given a "set speed" command for a particular device,
+   the underlying system service is called to set the speed; its return
+   code is checked and the SET SPEED command fails if the return code
+   indicates failure. Regardless of the system service return status, the
+   device's speed is then read back and if it does not match the speed
+   that was requested, an error message is printed and the command fails.
+
+   Even when the command succeeds, this does not guarantee successful
+   operation at a particular speed, especially a high one. That depends
+   on electricity, information theory, etc. How long is the cable, what
+   is its capacitance, how well is it shielded, etc, not to mention that
+   every connection has two ends and its success depends on both of them.
+   (With the obvious caveats about internal modems, is the cable really
+   connected, interrupt conflicts, etc etc etc).
+
+   Note, in particular, that there is a certain threshold above which
+   modems can not "autobaud" -- i.e. detect the serial interface speed
+   when you type AT (or whatever else the modem's recognition sequence
+   might be). Such modems need to be engaged at a lower speed (say 2400
+   or 9600 or even 115200 -- any speed below their autobaud threshold)
+   and then must be given a modem-specific command (which can be found in
+   the modem manual) to change their interface speed to the desired
+   higher speed, and then the software must also be told to change to the
+   new, higher speed.
+
+   For additional information, read [548]Section 9.5 of the Installation
+   Instructions, plus any platform-specific notes in [549]Section 3
+   above.
+    ________________________________________________________________________
+
+  7. COMMUNICATIONS AND DIALING
+
+   [ [550]Top ] [ [551]Contents ] [ [552]Next ] [ [553]Previous ]
+
+  7.1. Serial Ports and Modems
+
+   If you SET LINE to a serial port modem-control device that has nothing
+   plugged in to it, or has a modem connected that is powered off, and
+   you have not given a prior SET MODEM TYPE or SET CARRIER-WATCH OFF
+   command, the SET LINE command is likely to hang. In most cases, you
+   can Ctrl-C out. If not, you'll have to kill C-Kermit from another
+   terminal.
+
+   Similarly, if you give a SET MODEM TYPE HAYES (or USR, or any other
+   modem type besides DIRECT, NONE, or UNKNOWN) and then SET LINE to an
+   empty port, the subsequent close (implicit or explicit) is liable to
+   hang or even crash (through no fault of Kermit's -- the hanging or
+   crashing is inside a system call such as cfsetospeed() or close()).
+
+   The SET CARRIER-WATCH command works as advertised only if the
+   underlying operating system and device drivers support this feature;
+   in particular only if a read() operation returns immediately with an
+   error code if the carrier signal goes away or, failing that, if
+   C-Kermit can obtain the modem signals from the device driver (you can
+   tell by giving a "set line" command to a serial device, and then a
+   "show communications" command -- if modem signals are not listed,
+   C-Kermit won't be able to detect carrier loss, the WAIT command will
+   not work, etc). Of course, the device itself (e.g. modem) must be
+   configured appropriately and the cables convey the carrier and other
+   needed signals, etc.
+
+   If you dial out from Unix system, but then notice a lot of weird
+   character strings being stuck into your session at random times
+   (especially if they look like +++ATQ0H0 or login banners or prompts),
+   that means that getty is also trying to control the same device.
+   You'll need to dial out on a device that is not waiting for a login,
+   or else disable getty on the device.
+
+   As of version 7.0, C-Kermit makes explicit checks for the Carrier
+   Detect signal, and so catches hung-up connections much better than 6.0
+   and earlier. However, it still can not be guaranteed to catch every
+   ever CD on-to-off transition. For example, when the HP-UX version of
+   C-Kermit is in CONNECT mode on a dialed connection and CARRIER-WATCH
+   ON or AUTO, and you turn off the modem, HP-UX is stuck in a read()
+   that never returns. (C-Kermit does not pop back to its prompt
+   automatically, but you can still escape back.)
+
+   If, on the other hand, you log out from the remote system, and it
+   hangs up, and CD drops on the local modem, C-Kermit detects this and
+   pops back to the prompt as it should. (Evidently there can be a
+   difference between CD and DSR turning off at the same time, versus CD
+   turning off while DSR stays on; experimentation with &S0/&S1/&S2 on
+   your modem might produce the desired results).
+
+   When Unix C-Kermit exits, it closes (and must close) the
+   communications device. If you were dialed out, this will most likely
+   hang up the connection. If you want to get out of Kermit and still use
+   Kermit's communication device, you have several choices:
+
+    1. Shell out from Kermit or suspend Kermit, and refer to the device
+       literally (as in "term -blah -blah < /dev/cua > /dev/cua").
+    2. Shell out from Kermit and use the device's file descriptor which
+       Kermit makes available to you in the \v(ttyfd) variable.
+    3. Use C-Kermit's REDIRECT command.
+    4. Use C-Kermit new EXEC /REDIRECT command.
+
+   If you are having trouble dialing:
+
+    1. Make sure the dialout line is configured correctly. More about
+       this below.
+    2. Make sure all necessary patches are installed for your operating
+       system.
+    3. If you can't dial on a "bidirectional" line, then configure it for
+       outbound-only (remove the getty) and try again. (The mechanisms --
+       if any -- for grabbing bidirectional lines for dialout vary wildly
+       among Unix implementations and releases, and C-Kermit -- which
+       runs on well over 300 different Unix variations -- makes no effort
+       to keep up with them; the recommended method for coping with this
+       situation is to wrap C-Kermit in a shell script that takes the
+       appropriate actions.)
+    4. Make sure C-Kermit's SET DIAL and SET MODEM parameters agree with
+       the modem you are actually using -- pay particular attention to
+       SET DIAL SPEED-MATCHING.
+    5. If MODEM HANGUP-METHOD is set to RS232-SIGNAL, change it to
+       MODEM-COMMAND. Or vice-versa.
+    6. Try SET DIAL HANGUP OFF before the DIAL command. Also, SET DIAL
+       DISPLAY ON to watch what's happening. See [554]Section 8 of the
+       [555]Installation Instructions.
+    7. Read pages 50-67 of [556]Using C-Kermit.
+    8. As a last resort, don't use the DIAL command at all; SET CARRIER
+       OFF and CONNECT to the modem and dial interactively, or write a
+       script program to dial the modem.
+
+   Make sure your dialout line is correctly configured for dialing out
+   (as opposed to login). The method for doing this is different for each
+   kind of Unix system. Consult your system documentation for configuring
+   lines for dialing out (for example, Sun SparcStation IPC users should
+   read the section "Setting up Modem Software" in the Desktop SPARC Sun
+   System & Network Manager's Guide; HP-9000 workstation users should
+   consult the manual Configuring HP-UX for Peripherals, etc).
+
+   Symptom: DIAL works, but a subsequent CONNECT command does not.
+   Diagnosis: the modem is not asserting Carrier Detect (CD) after the
+   connection is made, or the cable does not convey the CD signal. Cure:
+   Reconfigure the modem, replace the cable. Workaround: SET CARRIER OFF
+   (at least in System-V based Unix versions).
+
+   For Berkeley-Unix-based systems (4.3BSD and earlier), Kermit includes
+   code to use LPASS8 mode when parity is none, which is supposed to
+   allow 8-bit data and Xon/Xoff flow control at the same time. However,
+   as of edit 174, this code is entirely disabled because it is
+   unreliable: even though the host operating system might (or might not)
+   support LPASS8 mode correctly, the host access protocols (terminal
+   servers, telnet, rlogin, etc) generally have no way of finding out
+   about it and therefore render it ineffective, causing file transfer
+   failures. So as of edit 174, Kermit once again uses rawmode for 8-bit
+   data, and so there is no Xon/Xoff flow control during file transfer or
+   terminal emulation in the Berkeley-based versions (4.3 and earlier,
+   not 4.4).
+
+   Also on Berkeley-based systems (4.3 and earlier), there is apparently
+   no way to configure a dialout line for proper carrier handling, i.e.
+   ignore carrier during dialing, require carrier thereafter, get a fatal
+   error on any attempt to read from the device after carrier drops (this
+   is handled nicely in System V by manipulation of the CLOCAL flag). The
+   symptom is that carrier loss does not make C-Kermit pop back to the
+   prompt automatically. This is evident on the NeXT, for example, but
+   not on SunOS, which supports the CLOCAL flag. This is not a Kermit
+   problem, but a limitation of the underlying operating system. For
+   example, the cu program on the NeXT doesn't notice carrier loss
+   either, whereas cu on the Sun does.
+
+   On certain AT&T Unix systems equipped with AT&T modems, DIAL and
+   HANGUP don't work right. Workarounds: (1) SET DIAL HANGUP OFF before
+   attempting to dial; (2) If HANGUP doesn't work, SET LINE, and then SET
+   LINE <device> to totally close and reopen the device. If all else
+   fails, SET CARRIER OFF.
+
+   C-Kermit does not contain any particular support for AT&T DataKit
+   devices. You can use Kermit software to dial in to a DataKit line, but
+   C-Kermit does not contain the specialized code required to dial out
+   from a DataKit line. If the Unix system is connected to DataKit via
+   serial ports, dialout should work normally (e.g. set line /dev/ttym1,
+   set speed 19200, connect, and then see the DESTINATION: prompt, from
+   which you can connect to another computer on the DataKit network or to
+   an outgoing modem pool, etc). But if the Unix system is connected to
+   the DataKit network through the special DataKit interface board, then
+   SET LINE to a DataKit pseudodevice (such as /dev/dk031t) will not work
+   (you must use the DataKit "dk" or "dkcu" program instead). In C-Kermit
+   7.0 and later, you can make Kermit connections "though" dk or dkcu
+   using "set line /pty".
+
+   In some BSD-based Unix C-Kermit versions, SET LINE to a port that has
+   nothing plugged in to it with SET CARRIER ON will hang the program (as
+   it should), but it can't be interrupted with Ctrl-C. The interrupt
+   trap is correctly armed, but apparently the Unix open() call cannot be
+   interrupted in this case. When SET CARRIER is OFF or AUTO, the SET
+   LINE will eventually return, but then the program hangs
+   (uninterruptibly) when the EXIT or QUIT command (or, presumably,
+   another SET LINE command) is given. The latter is probably because of
+   the attempt to hang up the modem. (In edit 169, a timeout alarm was
+   placed around this operation.)
+
+   With SET DIAL HANGUP OFF in effect, the DIAL command might work only
+   once, but not again on the same device. In that case, give a CLOSE
+   command to close the device, and then another SET LINE command to
+   re-open the same device. Or rebuild your version of Kermit with the
+   -DCLSOPN compile-time switch.
+
+   The DIAL command says "To cancel: Type your interrupt character
+   (normally Ctrl-C)." This is just one example of where program messages
+   and documentation assume your interrupt character is Ctrl-C. But it
+   might be something else. In most (but not necessarily all) cases, the
+   character referred to is the one that generates the SIGINT signal. If
+   Ctrl-C doesn't act as an interrupt character for you, type the Unix
+   command "stty -a" or "stty all" or "stty everything" to see what your
+   interrupt character is. (Kermit could be made to find out what the
+   interrupt character is, but this would require a lot of
+   platform-dependent coding and #ifdefs, and a new routine and interface
+   between the platform-dependent and platform-independent parts of the
+   program.)
+
+   In general, the hangup operation on a serial communication device is
+   prone to failure. C-Kermit tries to support many, many different kinds
+   of computers, and there seems to be no portable method for hanging up
+   a modem connection (i.e. turning off the RS-232 DTR signal and then
+   turning it back on again). If HANGUP, DIAL, and/or Ctrl-\H do not work
+   for you, and you are a programmer, look at the tthang() function in
+   ckutio.c and see if you can add code to make it work correctly for
+   your system, and send the code to the address above. (NOTE: This
+   problem has been largely sidestepped as of edit 188, in which Kermit
+   first attempts to hang up the modem by "escaping back" via +++ and
+   then giving the modem's hangup command, e.g. ATH0, when DIAL
+   MODEM-HANGUP is ON, which is the default setting.)
+
+   Even when Kermit's modem-control software is configured correctly for
+   your computer, it can only work right if your modem is also configured
+   to assert the CD signal when it is connected to the remote modem and
+   to hang up the connection when your computer drops the DTR signal. So
+   before deciding Kermit doesn't work with your modem, check your modem
+   configuration AND the cable (if any) connecting your modem to the
+   computer -- it should be a straight-through modem cable conducting the
+   signals FG, SG, TD, RD, RTS, CTS, DSR, DTR, CD, and RI.
+
+   Many Unix systems keep aliases for dialout devices; for example,
+   /dev/acu might be an alias for /dev/tty00. But most of these Unix
+   systems also use UUCP lockfile conventions that do not take this
+   aliasing into account, so if one user assigns (e.g.) /dev/acu, then
+   another user can still assign the same device by referring to its
+   other name. This is not a Kermit problem -- Kermit must follow the
+   lockfile conventions used by the vendor-supplied software (cu, tip,
+   uucp).
+
+   The SET FLOW-CONTROL KEEP option should be given *before* any
+   communication (dialing, terminal emulation, file transfer,
+   INPUT/OUTPUT/TRANSMIT, etc) is attempted, if you want C-Kermit to use
+   all of the device's preexisting flow-control related settings. The
+   default flow-control setting is XON/XOFF, and it will take effect when
+   the first communication-related command is given, and a subsequent SET
+   FLOW KEEP command will not necessarily know how to restore *all* of
+   the device's original flow-control settings.
+
+  7.2. Network Connections
+
+   C-Kermit tries to use the 8th bit for data when parity is NONE, and
+   this generally works on real Unix terminal (tty) devices, but it often
+   does not work when the Unix system is accessed over a network via
+   telnet or rlogin protocols, including (in many cases) through terminal
+   servers. For example, an Encore computer with Annex terminal servers
+   only gives a 7-bit path if the rlogin protocol is selected in the
+   terminal server but it gives the full 8 bits if the proprietary RDP
+   protocol is used.
+
+   If file transfer does not work through a host to which you have
+   rlogin'd, use "rlogin -8" rather than "rlogin". If that doesn't work,
+   tell both Kermit programs to "set parity space".
+
+   The Encore TELNET server does not allow long bursts of input. When you
+   have a TELNET connection to an Encore, tell C-Kermit on the Encore to
+   SET RECEIVE PACKET-LENGTH 200 or thereabouts.
+    ________________________________________________________________________
+
+  8. HARDWARE FLOW CONTROL
+
+   [ [557]Top ] [ [558]Contents ] [ [559]Next ] [ [560]Previous ]
+
+   SET FLOW RTS/CTS is available in Unix C-Kermit only when the
+   underlying operating system provides an Application Program Interface
+   (API) for turning this feature on and off under program control, which
+   turns out to be a rather rare feature among Unix systems. To see if
+   your Unix C-Kermit version supports hardware flow control, type "set
+   flow ?" at the C-Kermit prompt, and look for "rts/cts" among the
+   options. Other common situations include:
+
+    1. The API is available, so "set flow rts/cts" appears as a valid
+       C-Kermit command, but it doesn't do anything because the device
+       driver (part of the operating system) was never coded to do
+       hardware flow control. This is common among System V R4
+       implementations (details below).
+    2. The API is not available, so "set flow rts/cts" does NOT appear as
+       a valid C-Kermit command, but you can still get RTS/CTS flow
+       control by selecting a specially named device in your SET LINE
+       command. Examples:
+          + NeXTSTEP: /dev/cufa instead of /dev/cua, /dev/cufb instead of
+            /dev/cub (68040 only; "man zs" for further info).
+          + IRIX: /dev/ttyf2 instead of /dev/ttyd2 or /dev/ttym2 ("man 7
+            serial").
+    3. The API is available, doesn't work, but a workaround as in (2) can
+       be used.
+    4. The API is available, but Kermit doesn't know about it. In these
+       cases, you can usually use an stty command to enable RTS/CTS on
+       the device, e.g. "stty crtscts" or "stty ctsflow", "stty rtsflow",
+       before starting Kermit, and then tell Kermit to SET FLOW KEEP.
+    5. No API and no special device drivers. Hardware flow control is
+       completely unavailable.
+
+   System V R4 based Unixes are supposed to supply a <termiox.h> file,
+   which gives Kermit the necessary interface to command the terminal
+   driver to enable/disable hardware flow control. Unfortunately, but
+   predictably, many implementations of SVR4 whimsically place this file
+   in /usr/include/sys rather than /usr/include (where SVID clearly
+   specifies it should be; see SVID, Third Edition, V1, termiox(BA_DEV).
+   Thus if you build C-Kermit with any of the makefile entries that
+   contain -DTERMIOX or -DSTERMIOX (the latter to select
+   <sys/termiox.h>), C-Kermit will have "set flow rts/cts" and possibly
+   other hardware flow-control related commands. BUT... That does not
+   necessarily mean that they will work. In some cases, the underlying
+   functions are simply not coded into the operating system.
+
+   WARNING: When hardware flow control is available, and you enable in
+   Kermit on a device that is not receiving the CTS signal, Kermit can
+   hang waiting for CTS to come up. This is most easily seen when the
+   local serial port has nothing plugged in to it, or is connected to an
+   external modem that is powered off.
+    ________________________________________________________________________
+
+  9. TERMINAL CONNECTION AND KEY MAPPING
+
+   [ [561]Top ] [ [562]Contents ] [ [563]Next ] [ [564]Previous ]
+
+   C-Kermit is not a terminal emulator. Refer to page 147 of [565]Using
+   C-Kermit, 2nd Edition: "Most versions of C-Kermit -- Unix, VMS,
+   AOS/VS, VOS, etc -- provide terminal connection without emulation.
+   These versions act as a 'semitransparent pipe' between the remote
+   computer and your terminal, terminal emulator, console driver, or
+   window, which in turn emulates (or is) a specific kind of terminal."
+   The environment in which you run C-Kermit is up to you.
+
+   If you are an X Windows user, you should be aware of an alternative to
+   xterm that supports VT220 emulation, from Thomas E. Dickey:
+
+  [566]http://dickey.his.com/xterm/xterm.html
+
+   Unix C-Kermit's SET KEY command currently can not be used with keys
+   that generate "wide" scan codes or multibyte sequences, such as
+   workstation function or arrow keys, because Unix C-Kermit does not
+   have direct access to the keyboard.
+
+   However, many Unix workstations and/or console drivers provide their
+   own key mapping feature. With xterm, for example, you can use
+   'xmodmap' ("man xmodmap" for details); here is an xterm mapping to map
+   the Sun keyboard to DEC VT200 values for use with VT-terminal oriented
+   applications like VMS EVE:
+
+  keycode 101=KP_0
+  keycode 119=KP_1
+  keycode 120=KP_2
+  keycode 121=KP_3
+  keycode 98=KP_4
+  keycode 99=KP_5
+  keycode 100=KP_6
+  keycode 75=KP_7
+  keycode 76=KP_8
+  keycode 77=KP_9
+  keycode 52=KP_F1
+  keycode 53=KP_F2
+  keycode 54=KP_F3
+  keycode 57=KP_Decimal
+  keycode 28=Left
+  keycode 29=Right
+  keycode 30=KP_Separator
+  keycode 105=KP_F4
+  keycode 78=KP_Subtract
+  keycode 8=Left
+  keycode 10=Right
+  keycode 32=Up
+  keycode 33=Down
+  keycode 97=KP_Enter
+
+   Users of Linux consoles can use loadkeys ("man dumpkeys loadkeys
+   keytables" for details. The format used by loadkeys is compatible with
+   that used by Xmodmap, although it is not definitely certain that the
+   keycodes are compatible for different keyboard types (e.g. Sun vs HP
+   vs PC, etc).
+    ________________________________________________________________________
+
+  10. FILE TRANSFER
+
+   [ [567]Top ] [ [568]Contents ] [ [569]Next ] [ [570]Previous ]
+
+   If uploads (or downloads) fail immediately, give the CAUTIOUS command
+   to Kermit and try again. If they still fail, then try SET PREFIXING
+   ALL. If they still fail, try SET PARITY SPACE. If they still fail, try
+   ROBUST.
+
+   If reception (particularly of large files and/or binary files) begins
+   successfully but then fail constently after a certain amount of bytes
+   have been sent, check:
+
+     * Your ulimit ("ulimit -a")
+     * The amount of available space on the target disk ("df ." or "df -k
+       .")
+     * Your personal disk quota (platform- and site-dependent)
+     * The maximum file size on the receiver's file system (e.g. 2GB in
+       old verions the Linux VFS file system, and/or in applications that
+       have not been recoded to use new "large file" APIs).
+     * If it's an NFS-mounted disk (if so, try uploading to a local disk)
+     * Is there an "idle limit" on the receiving end?
+
+   If none of these seem to explain it, then the problem is not size
+   related, but reflects some clash between the file contents and the
+   characteristics of the connection, in which case follow the
+   instructions in the first paragraph of this section.
+
+   Suppose two copies of Kermit are receiving files into the same
+   directory, and the files have the same name, e.g. "foo.bar". Whichever
+   one starts first opens an output file called "foo.bar". The second one
+   sees there is already a foo.bar file, and so renames the existing
+   foo.bar to foo.bar.~1~ (or whatever). When the first file has been
+   received completely, Kermit goes to change its modification time and
+   permissions to those given by the file sender in the Attribute packet.
+   But in Unix, the APIs for doing this take a filename, not a file
+   descriptor. Since the first Kermit's file has been renamed, and the
+   second Kermit is using the original name, the first Kermit changes the
+   modtime and permissions of the second Kermit's file, not its own.
+   Although there might be a way to work around this in the code, e.g.
+   using inode numbers to keep track of which file is which, this would
+   be tricky and most likely not very portable. It's better to set up
+   your application to prevent such things from happening, which is easy
+   enough using the script language, filename templates, etc.
+
+   Suppose you start C-Kermit with a command-line argument to send or
+   receive a file (e.g. "kermit -r") and then type Ctrl-\c immediately
+   afterwards to escape back and initiate the other end of the transfer,
+   BUT your local Kermit's escape character is not Ctrl-\. In this case,
+   the local Kermit passes the Ctrl-\ to the remote system, and if this
+   is Unix, Ctrl-\ is likely to be its SIGQUIT character, which causes
+   the current program to halt and dump core. Well, just about the first
+   thing C-Kermit does when it starts is to disable the SIGQUIT signal.
+   However, it is still possible for SIGQUIT to cause Kermit to quit and
+   dump core if it is delivered while Kermit is being loaded or started,
+   before the signal can be disabled. There's nothing Kermit itself can
+   do about this, but you can prevent it from happening by disabling
+   SIGQUIT in your Unix session. The command is usually something like:
+
+  stty quit undef
+
+   Unix C-Kermit does not reject incoming files on the basis of size.
+   There appears to be no good (reliable, portable) way to determine in
+   advance how much disk space is available, either on the device, or
+   (when quotas or other limits are involved) to the user.
+
+   Unix C-Kermit discards all carriage returns from incoming files when
+   in text mode.
+
+   If C-Kermit has problems creating files in writable directories when
+   it is installed setuid or setgid on BSD-based versions of Unix such as
+   NeXTSTEP 3.0, it probably needs to be rebuilt with the -DSW_ACC_ID
+   compilation switch.
+
+   If you SET FILE DISPLAY FULLSCREEN, and C-Kermit complains "Sorry,
+   terminal type not supported", it means that the terminal library
+   (termcap or termlib) that C-Kermit was built with does not know about
+   a terminal whose name is the current value of your TERM environment
+   variable. If this happens, but you want to have the fullscreen file
+   transfer display, EXIT from C-Kermit and set a Unix terminal type from
+   among the supported values that is also supported by your terminal
+   emulator, or else have an entry for your terminal type added to the
+   system termcap and/or terminfo database.
+
+   If you attempt to suspend C-Kermit during local-mode file transfer and
+   then continue it in the background (via bg), it will block for "tty
+   output" if you are using the FULLSCREEN file transfer display. This is
+   apparently a problem with curses. Moving a local-mode file transfer
+   back and forth between foreground and background works correctly,
+   however, with the SERIAL, CRT, BRIEF, or NONE file transfer displays.
+
+   If C-Kermit's command parser no longer echoes, or otherwise acts
+   strangely, after returning from a file transfer with the fullscreen
+   (curses) display, and the curses library for your version of Unix
+   includes the newterm() function, then try rebuilding your version of
+   C-Kermit with -DCK_NEWTERM. Similarly if it echoes doubly, which might
+   even happen during a subsequent CONNECT session. If rebuilding with
+   -DCK_NEWTERM doesn't fix it, then there is something very strange
+   about your system's curses library, and you should probably not use
+   it. Tell C-Kermit to SET FILE DISPLAY CRT, BRIEF, or anything else
+   other than FULLSCREEN, and/or rebuild without -DCK_CURSES, and without
+   linking with (termlib and) curses. Note: This problem seemed to have
+   escalated in C-Kermit 7.0, and -DCK_NEWTERM had to be added to many
+   builds that previously worked without it: Linux, AIX 4.1, DG/UX, etc.
+   In the Linux case, it is obviously because of changes in the (n)curses
+   library; the cause in the other cases is not known.
+
+   C-Kermit creates backup-file names (such as "oofa.txt.~1~") based on
+   its knowledge of the maximum filename length on the platform where it
+   is running, which is learned at compile time, based on MAXNAMLEN or
+   equivalent symbols from the system header files. But suppose C-Kermit
+   is receiving files on a Unix platform that supports long filenames,
+   but the incoming files are being stored on an NFS-mounted file system
+   that supports only short names. NFS maps the external system to the
+   local APIs, so C-Kermit has no way of knowing that long names will be
+   truncated. Or that C-Kermit is running on a version of Unix that
+   supports both long-name and short-name file systems simultaneously
+   (such as HP-UX 7.00). This can cause unexpected behavior when creating
+   backup files, or worse. For example, you are sending a group of files
+   whose names are differentiated only by characters past the point at
+   which they would be truncated, each file will overwrite the previous
+   one upon arrival.
+    ________________________________________________________________________
+
+  11. EXTERNAL FILE TRANSFER PROTOCOLS
+
+   [ [571]Top ] [ [572]Contents ] [ [573]Next ] [ [574]Previous ]
+
+   SECTION CONTENTS
+
+  11.1. [575]C-Kermit as an External Protocol
+  11.2. [576]Invoking External Protocols from C-Kermit
+
+   Unix C-Kermit can be used in conjunction with other communications
+   software in various ways. C-Kermit can be invoked from another
+   communications program as an "external protocol", and C-Kermit can
+   also invoke other communication software to perform external
+   protocols.
+
+   This sort of operation makes sense only when you are dialing out from
+   your Unix system (or making a network connection from it). If the Unix
+   system is the one you have dialed in to, you don't need any of these
+   tricks. Just run the desired software on your Unix system instead of
+   Kermit. When dialing out from a Unix system, the difficulty is getting
+   two programs to share the same communication device in spite of the
+   Unix UUCP lockfile mechanism, which would normally prevent any
+   sharing, and preventing the external protocol from closing (and
+   therefore hanging up) the device when it exits back to the program
+   that invoked it.
+
+  11.1. C-KERMIT AS AN EXTERNAL PROTOCOL
+
+   [ [577]Top ] [ [578]Contents ] [ [579]Section Contents ] [ [580]Next ]
+
+   (This section deleted; see [581]Using C-Kermit, 2nd Ed, Chapter 14.)
+
+   "pcomm" is a general-purpose terminal program that provides file
+   transfer capabilities itself (X- and YMODEM variations) and the
+   ability to call on external programs to do file transfers (ZMODEM and
+   Kermit, for example). You can tell pcomm the command to send or
+   receive a file with an external protocol:
+                        Send                            Receive  
+        ZMODEM          sz filename                     rz
+        Kermit          kermit -s filename              kermit -r
+
+   pcomm runs external programs for file transfer by making stdin and
+   stdout point to the modem port, and then exec-ing "/bin/sh -c xxx"
+   (where xxx is the appropriate command). However, C-Kermit does not
+   treat stdin and stdout as the communication device unless you instruct
+   it:
+
+
+                        Send                            Receive  
+        Kermit          kermit -l 0 -s filename         kermit -l 0 -r
+
+   The "-l 0" option means to use file descriptor 0 for the communication
+   device.
+
+   In general, any program can pass any open file descriptor to C-Kermit
+   for the communication device in the "-l" command-line option. When
+   Kermit is given a number as the argument to the "-l" option, it simply
+   uses it as a file descriptor, and it does not attempt to close it upon
+   exit.
+
+   Here's another example, for Seyon (a Linux communication program).
+   First try the technique above. If that works, fine; otherwise... If
+   Seyon does not give you a way to access and pass along the file
+   descriptor, but it starts up the Kermit program with its standard i/o
+   redirected to its (Seyon's) communications file descriptor, you can
+   also experiment with the following method, which worked here in brief
+   tests on SunOS. Instead of having Seyon use "kermit -r" or "kermit -s
+   filename" as its Kermit protocol commands, use something like this
+   (examples assume C-Kermit 6.0):
+
+   For serial connections:
+
+  kermit -YqQl 0 -r                     <-- to receive
+  kermit -YqQl 0 -s filename(s)         <-- to send one or more files
+
+   For Telnet connections:
+
+  kermit -YqQF 0 -r                     <-- to receive
+  kermit -YqQF 0 -s filename(s)         <-- to send one or more files
+
+   Command line options:
+
+  Y    - skip executing the init file
+  Q    - use fast file transfer settings (default in 8.0)
+  l 0  - transfer files using file descriptor 0 for a serial connection
+  F 0  - transfer files using file descriptor 0 for a Telnet connection
+  q    - quiet - no messages
+  r    - receive
+  s    - send
+
+  11.2. INVOKING EXTERNAL PROTOCOLS FROM C-KERMIT
+
+   [ [582]Top ] [ [583]Contents ] [ [584]Section Contents ] [
+   [585]Previous ]
+
+     (This section is obsolete, but not totally useless. See Chapter 14
+     of [586]Using C-Kermit, 2nd Edition). 
+
+   After you have opened a communication link with C-Kermit's SET LINE
+   (SET PORT) or SET HOST (TELNET) command, C-Kermit makes its file
+   descriptor available to you in the \v(ttyfd) variable so you can pass
+   it along to other programs that you RUN from C-Kermit. Here, for
+   example, C-Kermit runs itself as an external protocol:
+
+  C-Kermit>set modem type hayes
+  C-Kermit>set line /dev/acu
+  C-Kermit>set speed 2400
+  C-Kermit>dial 7654321
+   Call complete.
+  C-Kermit>echo \v(ttyfd)
+   3
+  C-Kermit>run kermit -l \v(ttyfd)
+
+   Other programs that accept open file descriptors on the command line
+   can be started in the same way.
+
+   You can also use your shell's i/o redirection facilities to assign
+   C-Kermit's open file descriptor (ttyfd) to stdin or stdout. For
+   example, old versions of the Unix ZMODEM programs, sz and rz, when
+   invoked as external protocols, expect to find the communication device
+   assigned to stdin and stdout with no option for specifying any other
+   file descriptor on the sz or rz command line. However, you can still
+   invoke sz and rz as exterior protocols from C-Kermit if your current
+   shell ($SHELL variable) is ksh (the Korn shell) or bash (the
+   Bourne-Again shell), which allows assignment of arbitrary file
+   descriptors to stdin and stdout:
+
+  C-Kermit> run rz <&\v(ttyfd) >&\v(ttyfd)
+
+   or:
+
+  C-Kermit> run sz oofa.zip <&\v(ttyfd) >&\v(ttyfd)
+
+   In version 5A(190) and later, you can use C-Kermit's REDIRECT command,
+   if it is available in your version of C-Kermit, to accomplish the same
+   thing without going through the shell:
+
+  C-Kermit> redirect rz
+
+   or:
+
+  C-Kermit> redirect sz oofa.zip
+
+   A complete set of rz,sz,rb,sb,rx,sx macros for Unix C-Kermit is
+   defined in the file ckurzsz.ini. It automatically chooses the best
+   redirection method (but is redundant since C-Kermit 6.0, which now has
+   built-in support for external protocols via its SET PROTOCOL command).
+
+   Note that external protocols can be used on C-Kermit SET LINE or SET
+   HOST connections only if they operate through standard input and
+   standard output. If they open their own connections, Kermit can't
+   redirect them over its own connection.
+    ________________________________________________________________________
+
+  12. SECURITY
+
+   [ [587]Top ] [ [588]Contents ] [ [589]Next ] [ [590]Previous ]
+
+   As of version 7.0, C-Kermit supports a wide range of security options
+   for authentication and encryption: Kerberos 4, Kerberos 5 / GSSAPI,
+   SSL/TLS, and SRP. See the separate [591]security document for details.
+    ________________________________________________________________________
+
+  13. MISCELLANEOUS USER REPORTS
+
+   [ [592]Top ] [ [593]Contents ] [ [594]Next ] [ [595]Previous ]
+
+Date: Thu, 12 Mar 92 1:59:25 MEZ
+From: Walter Mecky <walter@rent-a-guru.de>
+Subject: Help.Unix.sw
+To: svr4@pcsbst.pcs.com, source@usl.com
+
+PRODUCT:        Unix
+RELEASE:        Dell SVR4 V2.1 (is USL V3.0)
+MACHINE:        AT-386
+PATHNAME:       /usr/lib/libc.so.1
+                /usr/ccs/lib/libc.a
+ABSTRACT:       Function ttyname() does not close its file descriptor
+DESCRIPTION:
+        ttyname(3C) opens /dev but never closes it. So if it is called
+        often enough the open(2) in ttyname() fails. Because the broken
+        ttyname() is in the shared lib too all programs using it can
+        fail if they call it often enough. One important program is
+        uucico which calls ttyname for every file it transfers.
+
+   Here is a little test program if your system has the bug:
+
+#include <stdlib.h>
+#include <stdio.h>
+main() {
+    int i = 0;
+    while (ttyname(0) != NULL)
+      i++;
+    perror("ttyname");
+    printf("i=%d\n", i);
+}
+
+   If this program runs longer than some seconds you don't have the bug.
+
+   WORKAROUND: None FIX: Very easy if you have source code.
+
+   Another user reports some more explicit symptoms and recoveries:
+
+> What happens is when invoking ckermit we get one of the following
+> error messages:
+>   You must set line
+>   Not a tty
+>   No more processes.
+> One of the following three actions clears the peoblem:
+>   shutdown -y -g0 -i6
+>   kill -9 the ttymon with the highest PID
+>   Invoke sysadm and disable then enable the line you want to use.
+> Turning off respawn of sac -t 300 and going to getty's and uugetty's
+> does not help.
+>
+> Also C-Kermit reports "?timed out closing /dev/ttyxx".
+> If this happens all is well.
+
+------------------------------
+
+   (Note: the following problem also occurs on SGI and probably many
+   other Unix systems):
+
+   From: James Spath <spath@jhunix.hcf.jhu.edu>
+   To: Info-Kermit-Request@cunixf.cc.columbia.edu
+   Date: Wed, 9 Sep 1992 20:20:28 -0400
+   Subject: C-Kermit vs uugetty (or init) on Sperry 5000
+
+   We have successfully compiled the above release on a Unisys/Sperry
+   5000/95. We used the sys5r3 option, rather than sys5r2 since we have
+   VR3 running on our system. In order to allow dialout access to
+   non-superusers, we had to do "chmod 666 /dev/tty###, where it had been
+   -rw--w--w- (owned by uucp), and to do "chmod +w /usr/spool/locks". We
+   have done text and binary file transfers through local and remote
+   connections.
+
+   The problem concerning uucp ownership and permissions is worse than I
+   thought at first. Apparently init or uugetty changes the file
+   permissions after each session. So I wrote the following C program to
+   open a set of requested tty lines. I run this for any required
+   outgoing line prior to a Kermit session.
+
+   ------ cut here -------
+/* opentty.c -- force allow read on tty lines for modem i/o */
+/* idea from: restrict.c -- System 5 Admin book Thomas/Farrow p. 605 */
+/* /jes jim spath {spath@jhunix.hcj.jhu.edu } */
+/* 08-Sep-92 NO COPYRIGHT. */
+/* this must be suid to open other tty lines */
+
+/* #define DEBUG */
+#define TTY "/dev/tty"
+#define LOK "/usr/spool/locks/LCK..tty"
+#include <stdio.h>
+
+/* allowable lines: */
+#define TOTAL_LINES 3
+static char allowable[TOTAL_LINES][4] = { "200", "201", "300" };
+static int total=TOTAL_LINES;
+int allow;
+
+/* states: */
+#define TTY_UNDEF 0
+#define TTY_LOCK  1
+#define TTY_OKAY  2
+
+main(argc, argv)
+int argc; char *argv[]; {
+    char device[512];
+    char lockdev[512];
+    int i;
+    if (argc == 1) {
+        fprintf(stderr, "usage: open 200 [...]\n");
+    }
+    while (--argc > 0 && (*++argv) != NULL ) {
+#ifdef DEBUG
+        fprintf(stderr, "TRYING: %s%s\n", TTY, *argv);
+#endif
+        sprintf(device, "%s%s", TTY, *argv);
+        sprintf(lockdev, "%s%s", LOK, *argv);
+        allow = TTY_UNDEF; i = 0;
+        while (i <= total) { /* look at all defined lines */
+#ifdef DEBUG
+            fprintf(stderr, "LOCKFILE? %s?\n", lockdev);
+#endif
+            if (access(lockdev, 00) == 0) {
+                allow=TTY_LOCK;
+                break;
+            }
+#ifdef DEBUG
+            fprintf(stderr, "DOES:%s==%s?\n", allowable[i], *argv);
+#endif
+            if (strcmp(allowable[i], *argv) == 0)
+              allow=TTY_OKAY;
+            i++;
+        }
+#ifdef DEBUG
+        fprintf(stderr, "allow=%d\n", allow);
+#endif
+        switch (allow) {
+          case TTY_UNDEF:
+            fprintf (stderr, "open: not allowed on %s\n", *argv);
+            break;
+          case TTY_LOCK:
+            fprintf (stderr, "open: device locked: %s\n", lockdev);
+            break;
+          case TTY_OKAY:
+            /* attempt to change mode on device */
+            if (chmod (device, 00666) < 0)
+              fprintf (stderr, "open: cannot chmod on %s\n", device);
+            break;
+          default:
+            fprintf (stderr, "open: FAULT\n");
+        }
+    }
+    exit (0);
+}
+    ________________________________________________________________________
+
+  14. THIRD-PARTY DRIVERS
+
+   [ [596]Top ] [ [597]Contents ] [ [598]Next ] [ [599]Previous ]
+
+   Unix versions, especially those for PCs (SCO, Unixware, etc) might be
+   augmented by third-party communication-board drivers from Digiboard,
+   Stallion, etc. These can sometimes complicate matters for Kermit
+   considerably since Kermit has no way of knowing that it is going
+   through a possibly nonstandard driver. Various examples are listed in
+   the earlier sections of this document; search for Stallion, Digiboard,
+   etc. Additionally:
+
+     * The Stallion Technologies EasyConnection serial board driver does
+       not always report the state of DSR as low. From Stallion (October
+       1997): "Unfortunately, this is a bug in our driver. We have
+       implemented all of the other TIOMC functions, eg DTR, DCD, RTS and
+       CTS, but not DSR. Our driver should report the actual state of DSR
+       on those of our cards that have a DSR signal. That the driver
+       always reports DSR as not asserted (0), is a bug in the driver.
+       The driver should be either reporting the state of DSR correctly
+       on those cards that support DSR or as always asserted (1) on those
+       cards that do not have a DSR signal. This will be fixed in a
+       future version of our drivers; at this time I cannot say when this
+       will be." And later, "As far as I can tell, we don't support the
+       termios/termiox ioctls that relate specifically to DSR and RI; all
+       the rest are supported. This will, as I mentioned earlier, be
+       fixed in the next release of our ATA software."
+       - World Wide Escalation Support, Stallion Technologies, Toowong
+       QLD, [600]support@stallion.oz.au.
+
+   Later (December 1997, from the same source):
+
+     * We have now released a new version of the ATA software, version
+       5.4.0. This version fixes the problem with the states of the DSR
+       and RI signals and how they were being reported by the driver.
+       This is the problem that you reported in October. The DSR signal
+       is reported correctly on those cards that support the DSR signal,
+       such as the early revision of the EasyIO card and the
+       EasyConnection 8D4 panel, and as always asserted on those cards
+       that do not support the DSR signal in the hardware. The new driver
+       is available from our Web site, [601]www.stallion.com, in the
+       /drivers/ata5/UnixWare directory.
+
+   [ [602]Top ] [ [603]Contents ] [ [604]C-Kermit Home ] [ [605]C-Kermit
+   8.0 Overview ] [ [606]Kermit Home ]
+     _________________________________________________________________
+
+   C-Kermit 8.0 Unix Hints and Tips / [607]The Kermit Project /
+   [608]Columbia University / [609]kermit@columbia.edu
+
+References
+
+   1. http://www.columbia.edu/kermit/
+   2. http://www.columbia.edu/
+   3. http://www.columbia.edu/kermit/ckubwr.html
+   4. mailto:kermit-support@columbia.edu
+   5. http://www.columbia.edu/kermit/ckermit.html
+   6. http://www.columbia.edu/kermit/ckuins.html
+   7. http://www.columbia.edu/kermit/ckututor.html
+   8. http://www.columbia.edu/kermit/ckubwr.html#x1
+   9. http://www.columbia.edu/kermit/ckubwr.html#x2
+  10. http://www.columbia.edu/kermit/ckubwr.html#x3
+  11. http://www.columbia.edu/kermit/ckubwr.html#x4
+  12. http://www.columbia.edu/kermit/ckubwr.html#x5
+  13. http://www.columbia.edu/kermit/ckubwr.html#x6
+  14. http://www.columbia.edu/kermit/ckubwr.html#x7
+  15. http://www.columbia.edu/kermit/ckubwr.html#x8
+  16. http://www.columbia.edu/kermit/ckubwr.html#x9
+  17. http://www.columbia.edu/kermit/ckubwr.html#x10
+  18. http://www.columbia.edu/kermit/ckubwr.html#x11
+  19. http://www.columbia.edu/kermit/ckubwr.html#x12
+  20. http://www.columbia.edu/kermit/ckubwr.html#x13
+  21. http://www.columbia.edu/kermit/ckubwr.html#x14
+  22. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+  23. http://www.columbia.edu/kermit/ckubwr.html#x3.18
+  24. http://www.columbia.edu/kermit/ckubwr.html#x3.19
+  25. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+  26. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+  27. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+  28. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+  29. http://www.columbia.edu/kermit/ckubwr.html#x3.13
+  30. http://www.columbia.edu/kermit/ckubwr.html#top
+  31. http://www.columbia.edu/kermit/ckubwr.html#contents
+  32. http://www.columbia.edu/kermit/ckubwr.html#x2
+  33. http://www.columbia.edu/kermit/ckubwr.html#x1.1
+  34. http://www.columbia.edu/kermit/ckubwr.html#x1.2
+  35. http://www.columbia.edu/kermit/ckubwr.html#x1.3
+  36. http://www.columbia.edu/kermit/ckubwr.html#x1.4
+  37. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+  38. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+  39. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+  40. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+  41. http://www.columbia.edu/kermit/ckcbwr.html
+  42. mailto:kermit-support@columbia.edu
+  43. http://www.columbia.edu/kermit/ckubwr.html#top
+  44. http://www.columbia.edu/kermit/ckubwr.html#contents
+  45. http://www.columbia.edu/kermit/ckubwr.html#x1.2
+  46. http://www.columbia.edu/kermit/ck60manual.html
+  47. http://www.columbia.edu/kermit/ckermit70.html
+  48. http://www.columbia.edu/kermit/ckermit80.html
+  49. http://www.columbia.edu/kermit/ckubwr.html#top
+  50. http://www.columbia.edu/kermit/ckubwr.html#contents
+  51. http://www.columbia.edu/kermit/ckubwr.html#x1
+  52. http://www.columbia.edu/kermit/ckubwr.html#x1.3
+  53. http://www.columbia.edu/kermit/ckubwr.html#x1.1
+  54. http://www.columbia.edu/kermit/support.html
+  55. http://www.columbia.edu/kermit/ckubwr.html#top
+  56. http://www.columbia.edu/kermit/ckubwr.html#contents
+  57. http://www.columbia.edu/kermit/ckubwr.html#x1
+  58. http://www.columbia.edu/kermit/ckubwr.html#x1.4
+  59. http://www.columbia.edu/kermit/ckubwr.html#x1.2
+  60. http://www.columbia.edu/kermit/ckubwr.html#top
+  61. http://www.columbia.edu/kermit/ckubwr.html#contents
+  62. http://www.columbia.edu/kermit/ckubwr.html#x1
+  63. http://www.columbia.edu/kermit/ckubwr.html#x1.3
+  64. http://www.columbia.edu/kermit/ckubwr.html#top
+  65. http://www.columbia.edu/kermit/ckubwr.html#contents
+  66. http://www.columbia.edu/kermit/ckubwr.html#x3
+  67. http://www.columbia.edu/kermit/ckubwr.html#x1
+  68. http://www.columbia.edu/kermit/ckubwr.html#top
+  69. http://www.columbia.edu/kermit/ckubwr.html#contents
+  70. http://www.columbia.edu/kermit/ckubwr.html#x4
+  71. http://www.columbia.edu/kermit/ckubwr.html#x2
+  72. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+  73. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+  74. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+  75. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+  76. http://www.columbia.edu/kermit/ckubwr.html#x3.4
+  77. http://www.columbia.edu/kermit/ckubwr.html#x3.5
+  78. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+  79. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+  80. http://www.columbia.edu/kermit/ckubwr.html#x3.8
+  81. http://www.columbia.edu/kermit/ckubwr.html#x3.9
+  82. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+  83. http://www.columbia.edu/kermit/ckubwr.html#x3.11
+  84. http://www.columbia.edu/kermit/ckubwr.html#x3.12
+  85. http://www.columbia.edu/kermit/ckubwr.html#x3.13
+  86. http://www.columbia.edu/kermit/ckubwr.html#x3.14
+  87. http://www.columbia.edu/kermit/ckubwr.html#x3.15
+  88. http://www.columbia.edu/kermit/ckubwr.html#x3.16
+  89. http://www.columbia.edu/kermit/ckubwr.html#x3.17
+  90. http://www.columbia.edu/kermit/ckubwr.html#x3.18
+  91. http://www.columbia.edu/kermit/ckubwr.html#x3.19
+  92. http://www.columbia.edu/kermit/ckubwr.html#x3.20
+  93. http://www.faqs.org/
+  94. http://aplawrence.com/Unixart/newtounix.html
+  95. http://www.columbia.edu/kermit/x3
+  96. mailto:kermit-support@columbia.edu
+  97. http://www.columbia.edu/kermit/support.html
+  98. http://www.columbia.edu/kermit/ckubwr.html#top
+  99. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 100. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 101. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 102. http://www.pcunix.com/
+ 103. http://www.columbia.edu/kermit/ckubwr.html#x3.0.1
+ 104. http://www.columbia.edu/kermit/ckubwr.html#x3.0.2
+ 105. http://www.columbia.edu/kermit/ckubwr.html#x3.0.3
+ 106. http://www.columbia.edu/kermit/ckubwr.html#x3.0.4
+ 107. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 108. http://www.columbia.edu/kermit/ckubwr.html#x3.0.6
+ 109. http://www.columbia.edu/kermit/ckubwr.html#top
+ 110. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 111. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 112. http://www.columbia.edu/kermit/ckubwr.html#x3.0.2
+ 113. http://www.columbia.edu/kermit/ckubwr.html#top
+ 114. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 115. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 116. http://www.columbia.edu/kermit/ckubwr.html#x3.0.3
+ 117. http://www.columbia.edu/kermit/ckubwr.html#x3.0.1
+ 118. http://www.linmodems.org/
+ 119. http://www.microsoft.com/hwdev/platform/PCdesign/LR/default.asp
+ 120. http://www.columbia.edu/kermit/ckubwr.html#top
+ 121. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 122. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 123. http://www.columbia.edu/kermit/ckubwr.html#x3.0.4
+ 124. http://www.columbia.edu/kermit/ckubwr.html#x3.0.2
+ 125. http://www.idir.net/~gromitkc/winmodem.html
+ 126. http://www.digi.com/
+ 127. http://www.columbia.edu/kermit/ckubwr.html#top
+ 128. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 129. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 130. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 131. http://www.columbia.edu/kermit/ckubwr.html#x3.0.3
+ 132. http://www.columbia.edu/kermit/ckubwr.html#top
+ 133. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 134. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 135. http://www.columbia.edu/kermit/ckubwr.html#x3.0.6
+ 136. http://www.columbia.edu/kermit/ckubwr.html#x3.0.4
+ 137. http://www.columbia.edu/kermit/ckubwr.html#top
+ 138. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 139. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 140. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 141. http://www.columbia.edu/kermit/ckubwr.html#top
+ 142. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 143. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 144. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 145. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 146. http://www.columbia.edu/kermit/ckubwr.html#x3.1.1
+ 147. http://www.columbia.edu/kermit/ckubwr.html#x3.1.2
+ 148. http://www.columbia.edu/kermit/ckubwr.html#x3.1.3
+ 149. http://www.columbia.edu/kermit/ckubwr.html#x3.1.4
+ 150. http://www.columbia.edu/kermit/ckubwr.html#x3.1.5
+ 151. http://www.emerson.emory.edu/services/aix-faq/
+ 152. http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.aix.html
+ 153. http://www.cis.ohio-state.edu/hypertext/faq/usenet/aix-faq/top.html
+ 154. http://aixpdslib.seas.ucla.edu/
+ 155. http://www.rootvg.net (AIX history)/
+ 156. ftp://rtfm.mit.edu/pub/usenet/news.answers/aix-faq/part1
+ 157. ftp://mirrors.aol.com/pub/rtfm/usenet-by-hierarchy/comp/unix/aix
+ 158. news:comp.unix.aix
+ 159. http://www.columbia.edu/kermit/ckubwr.html#top
+ 160. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 161. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 162. http://www.columbia.edu/kermit/ckubwr.html#x3.1.2
+ 163. http://www.columbia.edu/kermit/ckubwr.html#top
+ 164. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 165. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 166. http://www.columbia.edu/kermit/ckubwr.html#x3.1.3
+ 167. http://www.columbia.edu/kermit/ckubwr.html#x3.1.1
+ 168. http://www.columbia.edu/kermit/security.html#servers
+ 169. http://www.columbia.edu/kermit/ckubwr.html#top
+ 170. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 171. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 172. http://www.columbia.edu/kermit/ckubwr.html#x3.1.4
+ 173. http://www.columbia.edu/kermit/ckubwr.html#x3.1.2
+ 174. http://service.software.ibm.com/rs6000/
+ 175. http://www.columbia.edu/kermit/ckubwr.html#top
+ 176. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 177. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 178. http://www.columbia.edu/kermit/ckubwr.html#x3.1.5
+ 179. http://www.columbia.edu/kermit/ckubwr.html#x3.1.3
+ 180. http://www.columbia.edu/kermit/ckubwr.html#top
+ 181. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 182. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 183. http://www.columbia.edu/kermit/ckubwr.html#x3.1.4
+ 184. http://www.columbia.edu/kermit/ckubwr.html#top
+ 185. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 186. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 187. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 188. http://www.columbia.edu/kermit/ckubwr.html#x3.1
+ 189. http://www.columbia.edu/kermit/ckubwr.html#x3.2.0
+ 190. http://www.columbia.edu/kermit/ckubwr.html#x3.2.1
+ 191. http://www.columbia.edu/kermit/ckubwr.html#x3.2.2
+ 192. http://www.columbia.edu/kermit/ckubwr.html#x3.2.3
+ 193. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 194. http://www.columbia.edu/kermit/ckubwr.html#x3.2.5
+ 195. news:comp.sys.hp.hpux
+ 196. http://www.columbia.edu/kermit/ckubwr.html#top
+ 197. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 198. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 199. http://www.columbia.edu/kermit/ckubwr.html#x3.2.1
+ 200. http://www.columbia.edu/kermit/ckubwr.html#top
+ 201. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 202. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 203. http://www.columbia.edu/kermit/ckubwr.html#x3.2.2
+ 204. http://www.columbia.edu/kermit/ckubwr.html#x3.2.0
+ 205. ftp://kermit.columbia.edu/kermit/f/makefile
+ 206. http://www.columbia.edu/kermit/ckubwr.html#top
+ 207. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 208. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 209. http://www.columbia.edu/kermit/ckubwr.html#x3.2.3
+ 210. http://www.columbia.edu/kermit/ckubwr.html#x3.2.1
+ 211. http://www.columbia.edu/kermit/ckubwr.html#top
+ 212. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 213. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 214. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 215. http://www.columbia.edu/kermit/ckubwr.html#x3.2.2
+ 216. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.1
+ 217. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.2
+ 218. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.3
+ 219. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.4
+ 220. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.5
+ 221. http://www.columbia.edu/kermit/ckubwr.html#top
+ 222. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 223. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 224. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.2
+ 225. http://www.columbia.edu/kermit/ckubwr.html#x3.2.2
+ 226. http://www.columbia.edu/kermit/ckubwr.html#top
+ 227. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 228. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 229. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.3
+ 230. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.1
+ 231. http://www.columbia.edu/kermit/ckubwr.html#top
+ 232. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 233. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 234. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.4
+ 235. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.2
+ 236. http://www.columbia.edu/kermit/ckubwr.html#top
+ 237. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 238. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 239. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.5
+ 240. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.3
+ 241. http://www.columbia.edu/kermit/ckubwr.html#top
+ 242. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 243. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 244. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4.4
+ 245. http://www.columbia.edu/kermit/ckubwr.html#top
+ 246. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 247. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 248. http://www.columbia.edu/kermit/ckubwr.html#x3.2.4
+ 249. http://www.columbia.edu/kermit/ckubwr.html#top
+ 250. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 251. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 252. http://www.columbia.edu/kermit/ckubwr.html#x3.4
+ 253. http://www.columbia.edu/kermit/ckubwr.html#x3.2
+ 254. http://www.columbia.edu/kermit/ckubwr.html#x3.3.1
+ 255. http://www.columbia.edu/kermit/ckubwr.html#x3.3.2
+ 256. http://www.columbia.edu/kermit/ckubwr.html#x3.3.3
+ 257. http://www.columbia.edu/kermit/ckubwr.html#x3.3.4
+ 258. http://www.columbia.edu/kermit/ckubwr.html#x3.3.5
+ 259. http://www.columbia.edu/kermit/ckubwr.html#x3.3.6
+ 260. news:comp.os.linux.misc
+ 261. news:comp.os.linux.answers
+ 262. http://www.tldp.org/
+ 263. http://www.tldp.org/FAQ/Linux-FAQ.html
+ 264. http://www.tldp.org/HOWTO/Serial-HOWTO.html
+ 265. http://tldp.org/HOWTO/Modem-HOWTO.html
+ 266. ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO
+ 267. ftp://tsx-11.mit.edu/pub/linux/docs/HOWTO
+ 268. http://www.tldp.org/HOWTO/
+ 269. http://www.tldp.org/hmirrors.html
+ 270. http://www.redhat.com/apps/support/
+ 271. http://www.debian.org/support
+ 272. http://www.slackware.com/support/
+ 273. http://www.caldera.com/support/
+ 274. http://www.suse.com/support/
+ 275. http://www.mandrake.com/support/
+ 276. http://www.turbolinux.com/support/
+ 277. http://www.linmodems.org/
+ 278. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 279. http://linux.dreamtime.org/decnet/
+ 280. mailto:kermit-support@columbia.edu
+ 281. http://www.linmodems.org/
+ 282. http://www.columbia.edu/kermit/ckubwr.html#x3.0.2
+ 283. http://www.columbia.edu/kermit/security.html#servers
+ 284. http://www.columbia.edu/kermit/sshclient.html
+ 285. http://www.columbia.edu/kermit/ckubwr.html#top
+ 286. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 287. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 288. http://www.columbia.edu/kermit/ckubwr.html#x3.3.2
+ 289. http://www.columbia.edu/kermit/ckubwr.html#top
+ 290. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 291. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 292. http://www.columbia.edu/kermit/ckubwr.html#x3.3.3
+ 293. http://www.columbia.edu/kermit/ckubwr.html#x3.3.1
+ 294. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 295. http://www.columbia.edu/kermit/ckubwr.html#x6
+ 296. http://www.columbia.edu/kermit/ckubwr.html#x7
+ 297. http://www.columbia.edu/kermit/ckubwr.html#x8
+ 298. http://www.columbia.edu/kermit/ckuins.html#x10
+ 299. http://www.columbia.edu/kermit/ckuins.html#x11
+ 300. http://www.columbia.edu/kermit/ckuins.html
+ 301. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 302. http://linuxwww.db.erau.edu/mail_archives/linux-kernel/Mar_98/1441.html
+ 303. http://www.columbia.edu/kermit/ckubwr.html#top
+ 304. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 305. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 306. http://www.columbia.edu/kermit/ckubwr.html#x3.3.4
+ 307. http://www.columbia.edu/kermit/ckubwr.html#x3.3.2
+ 308. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 309. http://www.columbia.edu/kermit/ckfaq.html#term
+ 310. http://dickey.his.com/xterm/xterm.html
+ 311. http://dickey.his.com/xterm/xterm.html
+ 312. ftp://kermit.columbia.edu/kermit/f/xmodmap.txt
+ 313. http://www.columbia.edu/kermit/ckubwr.html#top
+ 314. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 315. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 316. http://www.columbia.edu/kermit/ckubwr.html#x3.3.5
+ 317. http://www.columbia.edu/kermit/ckubwr.html#x3.3.3
+ 318. http://www.columbia.edu/kermit/ckubwr.html#top
+ 319. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 320. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 321. http://www.columbia.edu/kermit/ckubwr.html#x3.3.6
+ 322. http://www.columbia.edu/kermit/ckubwr.html#x3.3.4
+ 323. http://www.columbia.edu/kermit/ckermit.html
+ 324. mailto:kermit-support@columbia.edu
+ 325. http://www.redhat.com/support/errata/RHBA-2001-153.html
+ 326. news:comp.protocols.kermit.misc
+ 327. http://www.columbia.edu/kermit/ckubwr.html#top
+ 328. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 329. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 330. http://www.columbia.edu/kermit/ckubwr.html#x3.3.5
+ 331. http://www.columbia.edu/kermit/ckubwr.html#top
+ 332. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 333. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 334. http://www.columbia.edu/kermit/ckubwr.html#x3.5
+ 335. http://www.columbia.edu/kermit/ckubwr.html#x3.3
+ 336. http://www.columbia.edu/kermit/ckubwr.html#top
+ 337. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 338. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 339. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 340. http://www.columbia.edu/kermit/ckubwr.html#x3.4
+ 341. news:comp.os.qnx
+ 342. http://www.columbia.edu/kermit/gkermit.html
+ 343. http://www.columbia.edu/kermit/ckuins.html#x10
+ 344. http://www.columbia.edu/kermit/ckuins.html
+ 345. http://www.columbia.edu/kermit/ckubwr.html#top
+ 346. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 347. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 348. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 349. http://www.columbia.edu/kermit/ckubwr.html#x3.5
+ 350. http://www.columbia.edu/kermit/ckubwr.html#x3.6.1
+ 351. http://www.columbia.edu/kermit/ckubwr.html#x3.6.2
+ 352. http://www.columbia.edu/kermit/ckubwr.html#x3.6.3
+ 353. http://www.columbia.edu/kermit/ckubwr.html#x3.6.4
+ 354. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+ 355. http://aplawrence.com/SCOFAQ/
+ 356. http://www.zenez.com/cgi-bin/scoprogfaq/faq.pl
+ 357. http://www.zenez.com/cgi-bin/scouw7faq/faq.pl
+ 358. http://zenez.pcunix.com/cgi-bin/scouw7faq/faq.pl
+ 359. http://pcunix.com/Unixart/modems.html
+ 360. http://www.freebird.org/faq/
+ 361. http://www.freebird.org/faq/developer.html
+ 362. http://support.caldera.com/caldera
+ 363. http://stage.caldera.com/ta/
+ 364. http://aplawrence.com/newtosco.html
+ 365. http://www.columbia.edu/kermit/ckubwr.html#x3.0.5
+ 366. http://www.columbia.edu/kermit/ckfaq.html#term
+ 367. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 368. http://www.columbia.edu/kermit/ckubwr.html#top
+ 369. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 370. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 371. http://www.columbia.edu/kermit/ckubwr.html#x3.6.1
+ 372. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 373. http://www.columbia.edu/kermit/ckubwr.html#top
+ 374. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 375. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 376. http://www.columbia.edu/kermit/ckubwr.html#x3.6.3
+ 377. http://www.columbia.edu/kermit/ckubwr.html#x3.6.1
+ 378. http://www.digi.com/
+ 379. ftp://ftp.fu-berlin.de/pub/unix/driver/fas
+ 380. http://www.columbia.edu/kermit/ckubwr.html#x14
+ 381. http://www.sco.com/
+ 382. ftp://ftp.sco.com/
+ 383. http://www.columbia.edu/kermit/ckubwr.html#top
+ 384. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 385. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 386. http://www.columbia.edu/kermit/ckubwr.html#x3.6.4
+ 387. http://www.columbia.edu/kermit/ckubwr.html#x3.6.2
+ 388. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+ 389. http://www.columbia.edu/kermit/ckubwr.html#top
+ 390. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 391. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 392. http://www.columbia.edu/kermit/ckubwr.html#x3.6.3
+ 393. http://www.columbia.edu/kermit/ckubwr.html#top
+ 394. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 395. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 396. http://www.columbia.edu/kermit/ckubwr.html#x3.8
+ 397. http://www.columbia.edu/kermit/ckubwr.html#x3.6
+ 398. http://www.columbia.edu/kermit/ckubwr.html#x3.7.1
+ 399. http://www.columbia.edu/kermit/ckubwr.html#x3.7.2
+ 400. http://www.columbia.edu/kermit/ckubwr.html#x3.7.3
+ 401. http://www.columbia.edu/kermit/ckubwr.html#x3.7.4
+ 402. http://www.columbia.edu/kermit/ckubwr.html#x3.7.5
+ 403. news:comp.unix.solaris
+ 404. http://access1.sun.com/
+ 405. http://docs.sun.com/
+ 406. http://www.sunhelp.com/
+ 407. http://www.wins.uva.nl/pub/solaris/solaris2/
+ 408. http://www.wins.uva.nl/cgi-bin/sfaq.cgi
+ 409. ftp://ftp.wins.uva.nl/pub/solaris
+ 410. http://www.science.uva.nl/pub/solaris/solaris2.html
+ 411. http://www.stokely.com/
+ 412. http://www.stokely.com/unix.sysadm.resources/faqs.sun.html
+ 413. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 414. http://www.columbia.edu/kermit/ckubwr.html#top
+ 415. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 416. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 417. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 418. http://www.columbia.edu/kermit/ckubwr.html#x3.7.2
+ 419. http://www.columbia.edu/kermit/ckubwr.html#top
+ 420. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 421. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 422. http://www.columbia.edu/kermit/ckubwr.html#x3.7.3
+ 423. http://www.columbia.edu/kermit/ckubwr.html#x3.7.1
+ 424. http://www.columbia.edu/kermit/ckubwr.html#top
+ 425. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 426. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 427. http://www.columbia.edu/kermit/ckubwr.html#x3.7.4
+ 428. http://www.columbia.edu/kermit/ckubwr.html#x3.7.2
+ 429. http://www.columbia.edu/kermit/ckubwr.html#top
+ 430. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 431. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 432. http://www.columbia.edu/kermit/ckubwr.html#x3.7.5
+ 433. http://www.columbia.edu/kermit/ckubwr.html#x3.7.3
+ 434. news:comp.os.vms
+ 435. http://www.columbia.edu/kermit/ckubwr.html#top
+ 436. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 437. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 438. http://www.columbia.edu/kermit/ckubwr.html#x3.7.6
+ 439. http://www.columbia.edu/kermit/ckubwr.html#x3.7.4
+ 440. http://www.columbia.edu/kermit/ckubwr.html#top
+ 441. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 442. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 443. http://www.columbia.edu/kermit/ckubwr.html#x3.7.5
+ 444. http://www.columbia.edu/kermit/ckubwr.html#top
+ 445. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 446. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 447. http://www.columbia.edu/kermit/ckubwr.html#x3.9
+ 448. http://www.columbia.edu/kermit/ckubwr.html#x3.7
+ 449. http://www.stokely.com/
+ 450. http://access1.sun.com/
+ 451. http://www.ludd.luth.se/~bear/project/sun/sun.hardware.txt
+ 452. ftp://ftp.netcom.com/pub/ru/rubicon/sun.hdwr.ref
+ 453. ftp://ftp.intnet.net/pub/SUN/Sun-Hardware-Ref
+ 454. http://www.columbia.edu/kermit/ckubwr.html#top
+ 455. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 456. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 457. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+ 458. http://www.columbia.edu/kermit/ckubwr.html#x3.8
+ 459. news:comp.unix.ultrix
+ 460. news:comp.sys.dec
+ 461. http://www.columbia.edu/kermit/ckubwr.html#top
+ 462. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 463. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 464. http://www.columbia.edu/kermit/ckubwr.html#x3.11
+ 465. http://www.columbia.edu/kermit/ckubwr.html#x3.9
+ 466. http://www.freebird.org/
+ 467. http://www.freebird.org/faq/
+ 468. news:comp.unix.unixware.misc
+ 469. news:comp.unix.sco.misc
+ 470. http://www.columbia.edu/kermit/ckubwr.html#x3.0
+ 471. ftp://kermit.columbia.edu/kermit/f/ckutio.c
+ 472. http://www.columbia.edu/kermit/ckubwr.html#top
+ 473. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 474. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 475. http://www.columbia.edu/kermit/ckubwr.html#x3.12
+ 476. http://www.columbia.edu/kermit/ckubwr.html#x3.10
+ 477. http://www.columbia.edu/kermit/ckubwr.html#top
+ 478. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 479. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 480. http://www.columbia.edu/kermit/ckubwr.html#x3.13
+ 481. http://www.columbia.edu/kermit/ckubwr.html#x3.11
+ 482. http://www.columbia.edu/kermit/ckubwr.html#top
+ 483. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 484. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 485. http://www.columbia.edu/kermit/ckubwr.html#x3.14
+ 486. http://www.columbia.edu/kermit/ckubwr.html#x3.12
+ 487. http://www.columbia.edu/kermit/ckubwr.html#top
+ 488. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 489. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 490. http://www.columbia.edu/kermit/ckubwr.html#x3.15
+ 491. http://www.columbia.edu/kermit/ckubwr.html#x3.13
+ 492. news:comp.sys.sgi.misc
+ 493. news:comp.sys.sgi.admin
+ 494. http://www.sgi.com/
+ 495. http://www-viz.tamu.edu/~sgi-faq/
+ 496. ftp://viz.tamu.edu/pub/sgi/faq/
+ 497. http://www.columbia.edu/kermit/ckuins.html
+ 498. http://freeware.sgi.com/Installable/gcc-2.95.2.html
+ 499. http://freeware.sgi.com/Installable/gcc-2.95.2.html
+ 500. http://www.columbia.edu/kermit/ckubwr.html#top
+ 501. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 502. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 503. http://www.columbia.edu/kermit/ckubwr.html#x3.16
+ 504. http://www.columbia.edu/kermit/ckubwr.html#x3.14
+ 505. news:comp.sys.be
+ 506. http://www.columbia.edu/kermit/ckubwr.html#top
+ 507. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 508. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 509. http://www.columbia.edu/kermit/ckubwr.html#x3.17
+ 510. http://www.columbia.edu/kermit/ckubwr.html#x3.15
+ 511. http://www.columbia.edu/kermit/ckubwr.html#top
+ 512. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 513. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 514. http://www.columbia.edu/kermit/ckubwr.html#x3.18
+ 515. http://www.columbia.edu/kermit/ckubwr.html#x3.16
+ 516. http://www.columbia.edu/kermit/ckubwr.html#top
+ 517. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 518. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 519. http://www.columbia.edu/kermit/ckubwr.html#x3.19
+ 520. http://www.columbia.edu/kermit/ckubwr.html#x3.17
+ 521. http://www.columbia.edu/kermit/ckubwr.html#top
+ 522. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 523. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 524. http://www.columbia.edu/kermit/ckubwr.html#x3.20
+ 525. http://www.columbia.edu/kermit/ckubwr.html#x3.18
+ 526. http://www.keyspan.com/products/usb/adapter/
+ 527. http://www.columbia.edu/kermit/ckuins.html
+ 528. http://cerebus.sandiego.edu/~jerry/UnixTips/
+ 529. http://www.columbia.edu/kermit/ckubwr.html#top
+ 530. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 531. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 532. http://www.columbia.edu/kermit/ckubwr.html#x3.19
+ 533. http://www.uni-giessen.de/faq/archiv/coherent-faq.general/msg00000.html
+ 534. http://www.columbia.edu/kermit/ckubwr.html#top
+ 535. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 536. http://www.columbia.edu/kermit/ckubwr.html#x5
+ 537. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 538. http://www.columbia.edu/kermit/ckccfg.html
+ 539. http://www.columbia.edu/kermit/ckubwr.html#top
+ 540. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 541. http://www.columbia.edu/kermit/ckubwr.html#x6
+ 542. http://www.columbia.edu/kermit/ckubwr.html#x4
+ 543. http://www.columbia.edu/kermit/ckuins.html
+ 544. http://www.columbia.edu/kermit/ckubwr.html#top
+ 545. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 546. http://www.columbia.edu/kermit/ckubwr.html#x7
+ 547. http://www.columbia.edu/kermit/ckubwr.html#x5
+ 548. http://www.columbia.edu/kermit/ckuins.html#9.5
+ 549. http://www.columbia.edu/kermit/ckubwr.html#x3
+ 550. http://www.columbia.edu/kermit/ckubwr.html#top
+ 551. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 552. http://www.columbia.edu/kermit/ckubwr.html#x8
+ 553. http://www.columbia.edu/kermit/ckubwr.html#x6
+ 554. http://www.columbia.edu/kermit/ckuins.html#x8
+ 555. http://www.columbia.edu/kermit/ckuins.html
+ 556. http://www.columbia.edu/kermit/ck60manual.html
+ 557. http://www.columbia.edu/kermit/ckubwr.html#top
+ 558. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 559. http://www.columbia.edu/kermit/ckubwr.html#x9
+ 560. http://www.columbia.edu/kermit/ckubwr.html#x7
+ 561. http://www.columbia.edu/kermit/ckubwr.html#top
+ 562. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 563. http://www.columbia.edu/kermit/ckubwr.html#x10
+ 564. http://www.columbia.edu/kermit/ckubwr.html#x8
+ 565. http://www.columbia.edu/kermit/ck60manual.html
+ 566. http://dickey.his.com/xterm/xterm.html
+ 567. http://www.columbia.edu/kermit/ckubwr.html#top
+ 568. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 569. http://www.columbia.edu/kermit/ckubwr.html#x11
+ 570. http://www.columbia.edu/kermit/ckubwr.html#x9
+ 571. http://www.columbia.edu/kermit/ckubwr.html#top
+ 572. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 573. http://www.columbia.edu/kermit/ckubwr.html#x12
+ 574. http://www.columbia.edu/kermit/ckubwr.html#x10
+ 575. http://www.columbia.edu/kermit/ckubwr.html#x11.1
+ 576. http://www.columbia.edu/kermit/ckubwr.html#x11.2
+ 577. http://www.columbia.edu/kermit/ckubwr.html#top
+ 578. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 579. http://www.columbia.edu/kermit/ckubwr.html#x11
+ 580. http://www.columbia.edu/kermit/ckubwr.html#x11.2
+ 581. http://www.columbia.edu/kermit/ck60manual.html
+ 582. http://www.columbia.edu/kermit/ckubwr.html#top
+ 583. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 584. http://www.columbia.edu/kermit/ckubwr.html#x11
+ 585. http://www.columbia.edu/kermit/ckubwr.html#x11.1
+ 586. http://www.columbia.edu/kermit/ck60manual.html
+ 587. http://www.columbia.edu/kermit/ckubwr.html#top
+ 588. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 589. http://www.columbia.edu/kermit/ckubwr.html#x13
+ 590. http://www.columbia.edu/kermit/ckubwr.html#x11
+ 591. http://www.columbia.edu/kermit/security.html
+ 592. http://www.columbia.edu/kermit/ckubwr.html#top
+ 593. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 594. http://www.columbia.edu/kermit/ckubwr.html#x14
+ 595. http://www.columbia.edu/kermit/ckubwr.html#x12
+ 596. http://www.columbia.edu/kermit/ckubwr.html#top
+ 597. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 598. http://www.columbia.edu/kermit/ckubwr.html#x15
+ 599. http://www.columbia.edu/kermit/ckubwr.html#x14
+ 600. mailto:support@stallion.oz.au
+ 601. http://www.stallion.com/
+ 602. http://www.columbia.edu/kermit/ckubwr.html#top
+ 603. http://www.columbia.edu/kermit/ckubwr.html#contents
+ 604. http://www.columbia.edu/kermit/ckermit.html
+ 605. http://www.columbia.edu/kermit/ck80.html
+ 606. http://www.columbia.edu/kermit/index.html
+ 607. http://www.columbia.edu/kermit/index.html
+ 608. http://www.columbia.edu/
+ 609. mailto:kermit@columbia.edu
diff --git a/ckermit-8.0.211/ckucmd.c b/ckermit-8.0.211/ckucmd.c
new file mode 100644
index 0000000..e1bca34
--- /dev/null
+++ b/ckermit-8.0.211/ckucmd.c
@@ -0,0 +1,7639 @@
+#include "ckcsym.h"
+
+char *cmdv = "Command package 8.0.157, 11 May 2003";
+
+/*  C K U C M D  --  Interactive command package for Unix  */
+
+/*
+  Author: Frank da Cruz (fdc@columbia.edu),
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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.
+*/
+
+#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 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"
+};
+
+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;
+#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 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 */
+
+#include <errno.h>			/* Error number symbols */
+
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO			/* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else
+#define APIRET ULONG
+#include <windows.h>
+#endif /* NT */
+#include "ckocon.h"
+#include <io.h>
+#endif /* OS2 */
+
+#ifdef NT
+#define stricmp _stricmp
+#endif /* NT */
+
+#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 <sys/syslog.h>
+#else  /* RTAIX */
+#include <syslog.h>
+#endif /* RTAIX */
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+#endif /* UNIX */
+#endif /* CKSYSLOG */
+
+/* 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 */
+
+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 */
+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 */
+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 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
+hasnopath(s) char * s; {
+    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  */
+
+static char * sprptr = NULL;
+
+static char *
+ckspread(s) char * s; {
+    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  */
+
+static int
+test(x,m) int x, m; { /*  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)
+
+  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
+kwdhelp(s,n,pat,pre,post,off,xhlp)
+    struct keytab s[]; int n, off, xhlp; char *pat, *pre, *post;
+/* 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 (ckstrcmp(s[i].kwd,pat,cc,0))
+	      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;
+}
+
+/*  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
+
+  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
+filhelp(n,pre,post,off,cmdirflg) int n, off; char *pre, *post; int cmdirflg; {
+    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 */
+#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);
+    }
+}
+
+/*  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 (!(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
+cmsetp(s) char *s; {
+    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
+prompt(f) xx_strp f; {
+    char *sx, *sy; int n;
+#ifdef CK_SSL
+    extern int ssl_active_flag, tls_active_flag;
+#endif /* CK_SSL */
+#ifdef OS2
+    extern int display_demo;
+
+    /* If there is a demo screen to be displayed, display it */
+    if (display_demo && xcmdsrc == 0) {
+        demoscrn(VCMD);
+        display_demo = 0;
+    }
+#endif /* OS2 */
+
+    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 */
+	debug(F101,"prompt sx","",sx);
+	debug(F101,"prompt sy","",sy);
+	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(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
+pushcmd(s) char * s; {			/* For use with IF command. */
+    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
+pushqcmd(s) char * s; {			/* For use with ELSE command. */
+    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
+cmini(d) int d; {
+#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
+untab(s) char *s; {
+    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
+*/
+int
+cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
+    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 = atoi(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 = atoi(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 = atoi(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
+cmofi(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
+    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
+o_again:
+#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 */
+
+    if (strcmp(s,CTTNAM) && (zchko(s) < 0)) { /* OK to write to console */
+#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.
+*/
+
+/*
+   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);
+}
+
+int
+cmifi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
+    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
+cmifip(xhlp,xdef,xp,wild,d,path,f)
+    char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; {
+    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
+cmdir(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
+    int wild;
+    return(cmifi2(xhlp,xdef,xp,&wild,0,NULL,f,1));
+}
+
+/* Like CMDIR but includes PATH search */
+
+int
+cmdirp(xhlp,xdef,xp,path,f) char *xhlp, *xdef, **xp; char * path; xx_strp f; {
+    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
+cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
+    char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; int dirflg; {
+    extern int recursive, diractive, cdactive, dblquo;
+    int i, x, itsadir, xc, expanded = 0, nfiles = 0, children = -1;
+    int qflag = 0;
+    long y;
+    char *sp = NULL, *zq, *np = NULL;
+    char *sv = NULL, *p = 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 = "";
+
+    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 */
+	    *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);
+	    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);
+		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 */
+			  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);
+		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. */
+	    y = dirflg ? itsadir : zchki(*xp); /* Now 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);
+	    free(sv);			/* done with this */
+	    sv = NULL;
+	    if (dirflg && y == 0) {
+		printf("?Not a directory - %s\n",*xp);
+#ifdef CKCHANNELIO
+		z_error = FX_ACC;
+#endif /* CKCHANNELIO */
+		return(-9);
+	    } else if (y == -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 (y == -2) {
+		if (!recursive) {
+		    if (np) free(np);
+		    if (d) 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 (y < 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);
+	    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<ESC>" */
+		/* 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<ESC>". */
+		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; char c;
+		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);
+		    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
+cmfld(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
+    int x, xc;
+    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);
+		/* 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 (**xp == NUL) x = -3; /* If still empty, return -3. */
+	    }
+	    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
+cmtxt(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; {
+
+    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;
+   xhlp     --  pointer to help string;
+   xdef     --  pointer to default keyword;
+   f        --  processing 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 =)
+ 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
+*/
+int
+cmkey(table,n,xhlp,xdef,f)
+/* cmkey */  struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
+    return(cmkey2(table,n,xhlp,xdef,"",f,1));
+}
+int
+cmkeyx(table,n,xhlp,xdef,f)
+/* cmkeyx */  struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
+    return(cmkey2(table,n,xhlp,xdef,"",f,0));
+}
+int
+cmswi(table,n,xhlp,xdef,f)
+/* cmswi */  struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
+    return(cmkey2(table,n,xhlp,xdef,"",f,4));
+}
+
+int
+cmkey2(table,n,xhlp,xdef,tok,f,pmsg)
+    struct keytab table[];
+    int n;
+    char *xhlp, *xdef;
+    char *tok;
+    xx_strp f;
+    int pmsg;
+{ /* cmkey2 */
+    extern int havetoken;
+    int i, tl, y, z = 0, zz, xc, wordlen = 0, cmswitch;
+    char *xp, *zq;
+
+    if (!xhlp) xhlp = "";
+    if (!xdef) xdef = "";
+
+    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);
+    /* debug(F101,"cmkey: cmdbuf","",cmdbuf);*/
+
+    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 {
+        rtimer();			 /* Reset timer */
+        zz = gtword((pmsg == 4) ? 1 : 0);/* Otherwise get a command word */
+    }
+
+    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) {
+		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 */
+	    }
+	    if (cmswitch && *atmbuf != '/') {
+		if (pmsg & 1) {
+		    bleep(BP_FAIL);
+                    printf("?Not a switch - %s\n",atmbuf);
+		}
+		cmflgs = -2;
+		return(-6);
+	    }
+	    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 */
+
+	    y = lookup(table,atmbuf,n,&z); /* Look up word in the table */
+	    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","",0);
+#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);
+		}
+	    }
+	    y = lookup(table,atmbuf,n,&z); /* Something in atmbuf */
+	    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 */
+		/* 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;
+		}
+		debug(F111,"cmkey partial z",atmbuf,z);
+		debug(F111,"cmkey partial n",atmbuf,n);
+		for (j = z+1; j < n; j++) {
+		    debug(F111,"cmkey partial j",table[j].kwd,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);
+		    debug(F111,"cmkey partial k",table[z].kwd,k);
+		    if (k < len)
+		      len = k; /* Length of longest common prefix */
+		}
+		debug(F111,"cmkey partial len",table[z].kwd,len);
+		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;
+	    debug(F110,"cmkey: addbuf",cmdbuf,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);
+		}
+	    }
+	    y = lookup(table,atmbuf,n,&z); /* Look up what we have so far. */
+	    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("%s%s", cmprom, cmdbuf);
+	    fflush(stdout);
+	    break;
+
+	  default:
+	    printf("\n%d - Unexpected return code from gtword\n",zz);
+	    return(cmflgs = -2);
+	}
+	zz = gtword((pmsg == 4) ? 1 : 0);
+	debug(F111,"cmkey gtword zz",atmbuf,zz);
+    }
+}
+
+int
+chktok(tlist) char *tlist; {
+    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;
+
+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 12
+
+#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 *
+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;
+/* cmdelta */ {
+    int zyy, zmo, zdd, zhh, zmm, zss;
+    long t1, t2, t3, t4;
+    long d1 = 0, d2, d3;
+    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 sin","",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);
+    }
+    if (dd < 1 || dd > mdays[mo]) {
+	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) {
+	mo += (sign * dmo);
+	if (mo > 12 || mo < 0) {
+	    yy += mo / 12;
+	    mo = mo % 12;
+	}
+    }
+    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
+delta2sec(s,result) char * s; long * result; {
+    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);
+}
+
+
+char *
+cmcvtdate(s,t) char * s; int t; {
+    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 * hour = "00", * min = "00", * sec = "00";
+    char datesep = 0;
+    char tmpbuf[8];
+    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 timbuf[16], *tb, cc;
+    char * dp = NULL;			/* Result pointer */
+
+    if (!s) s = "";
+    tmpbuf[0] = NUL;
+
+    while (*s == SP) s++;		/* Gobble any leading blanks */
+    if (isalpha(*s))			/* Remember if 1st char is a letter */
+      isletter = 1;
+
+    len = strlen(s);
+    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;
+    }
+    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);
+    }
+
+    /* Handle "today", "yesterday", "tomorrow", and +/- n units */
+
+    if (ckstrchr("TtYyNn",s[0])) {
+	int i, k, n, minus = 0;
+	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,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 */
+	    if (hh > 23) {		/* Offset crosses date boundary */
+		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);
+	    }
+	}
+	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 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
+cmvdate(d) char * d; {			/* Verify date-time */
+    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 *
+cmdiffdate(d1,d2) char * d1, * d2; {
+    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);
+}
+
+/* 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.
+    Returns:
+      Pointer to result if args valid, otherwise original arg pointer.
+*/
+char *
+shuffledate(p,opt) char * p; int opt; {
+    int len;
+    char ibuf[32];
+    static char obuf[48];
+    char c;
+    int yy, dd, mm;
+
+    if (!p) p = "";
+    if (!*p) p = ckdate();
+    if (opt < 1 || opt > 3)
+      return(p);
+    len = strlen(p);
+    if (len < 8 || len > 31) return(p);
+    if (opt == 3) {
+	ckstrncpy(obuf,p,48);
+	/* yyyymmdd hh:mm:ss */
+	/* 01234567890123456 */
+	/* yyyymmddhhmmss    */
+	obuf[8] = obuf[9];
+	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);
+    /* IGNORE WARNINGS ABOUT moname[] REFS OUT OF RANGE - it's prechecked. */
+    switch (opt) {
+      case 1:
+	sprintf(obuf,"%04d-%s-%02d%s",yy,moname[mm-1],dd,&ibuf[8]);
+	break;
+      case 2:
+	sprintf(obuf,"%02d-%s-%04d%s",dd,moname[mm-1],yy,&ibuf[8]);
+    }
+    return((char *)obuf);
+}
+
+/*  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 *
+ckcvtdate(p,t) char * p; int t; {
+    char * s;
+    if (!(s = cmcvtdate(p,t)))
+      return("<BAD_DATE_OR_TIME>");	/* \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
+cmdate(xhlp,xdef,xp,quiet,f) char *xhlp, *xdef, **xp; int quiet; xx_strp f; {
+    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
+cmrini(n) int n; {
+    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 *
+cmgetcmd(s) char * s; {
+    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
+addcmd(s) char * s; {
+    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
+savhistory(s,disp) char *s; int disp; {
+    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,
+    0,
+    NULL,
+    0
+};
+
+VOID
+cmfdbi(p,fc,s1,s2,s3,n1,n2,f,k,nxt)	/* Initialize an FDB */
+    struct FDB * p;
+    int fc;
+    char * s1, * s2, * s3;
+    int n1, n2;
+    xx_strp f;
+    struct keytab * k;
+    struct FDB * nxt; {
+
+    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
+cmfdb(fdbin) struct FDB * fdbin; {
+#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;
+    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 _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->kflags = (in->fcode == _CMKEY) ? cmkwflgs : 0;
+	    debug(F111,"cmfdb out->nresult",out->sresult,out->nresult);
+	    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 */
+    }
+}
+
+
+/*  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.
+
+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
+gtword(brk) int brk; {
+    int c;                              /* Current 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 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 COMMENT
+#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 /* COMMENT */
+    {
+	/* 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;
+        if (!c) {			/* If no char waiting in reparse buf */
+	    if (dpx && (!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++;
+
+	if (quote && (c == 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 (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 echof 2","",echof); */
+#ifdef BEBOX
+                if (echof) {
+                    putchar(c);		/* echo it. */
+                    fflush(stdout);
+                    fflush(stderr);
+                }
+#else
+                if (echof) {		/* echo it. */
+		    putchar((CHAR)c);
+		    if (timelimit)
+		      fflush(stdout);
+		}
+#endif /* BEBOX */
+                if (inword == 0) {      /* If leading, gobble it. */
+                    pp++;
+                    continue;
+                } else {                /* If terminating, return. */
+		    if ((!dq && ((*pp != lbrace) || (bracelvl == 0))) ||
+			(dq && dqn > 1 && *(bp-2) == '"')) {
+			np = bp;
+			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;
+			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) {
+                    putchar(c);		/* Echo it. */
+                    fflush(stdout);
+                    fflush(stderr);
+                }
+#else
+		if (echof) {
+		    putchar((CHAR)c);
+		    if (timelimit)
+		      fflush(stdout);
+		}
+#endif /* BEBOX */
+		if ((*pp != lbrace) || (bracelvl == 0)) {
+		    np = bp;
+		    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);
+		    }
+		    inword = cmflgs = 0;
+		    brkchar = c;
+		    return(4);
+		}
+            }
+            if (c == LF || c == 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;
+		    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;
+			    }
+			}
+		    }
+		}
+
+		switch (c) {
+		  case '?':		/* ?-Help */
+#ifndef NOSPL
+		    if (askflag)	/* No help in ASK response */
+		      break;
+#endif /* NOSPL */
+		    if (quoting
+			&& !kstartactive
+			&& !comment
+			) {
+			putchar((CHAR)c);
+			*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++)) {
+#ifdef isprint
+			  putchar((CHAR) (isprint(cx) ? cx : '^'));
+#else
+			  putchar((CHAR) ((cx >= SP && cx < DEL) ? cx : '^'));
+#endif /* isprint */
+		      }
+		      fflush(stdout);
+		      continue;
+		  }
+		}
+
+
+#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
+            if (echof) 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 == CR || c == LF || c == SP)) {
+		/* debug(F000,"gtword quote 2","",c); */
+		*bp++ = CMDQ;
+		linebegin = 0;		/* Not at beginning of line */
+		*bp = (c == SP ? SP : 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
+addbuf(cp) char *cp; {
+    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
+setatm(cp,fcode) char *cp; int fcode; {
+    char *ap, *xp, *dqp = NULL, lbrace, rbrace;
+    int bracelvl = 0, dq = 0;
+
+    register char * s;
+    register int n = 0;
+
+    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) {
+        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)
+	      break;
+	    if ((fcode == 2) && (*cp == '=' || *cp == ':')) break;
+	    if ((fcode != 3) && (*cp == LF || *cp == CR)) break;
+	}
+        *ap++ = *cp++;
+        cc++;
+    }
+    *ap = NUL;				/* Terminate the string. */
+    /* 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
+cmdgetc(timelimit) int timelimit; {	/* Get a character from the tty. */
+    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 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 _IO_file_flags			/* Linux */
+    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;
+#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 /* 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(CR);
+#endif /* IKSD */
+#endif /* OS2 */
+
+    putchar(c);				/* c is the terminating character */
+
+#ifdef WINTCP				/* what is this doing here? */
+    if (c == 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 == 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 == CR) putchar(NL);
+#endif /* OS2 */
+#endif /* COMMENT */
+#ifdef aegis
+    if (c == CR) putchar(NL);
+#endif /* aegis */
+#ifdef AMIGA
+    if (c == CR) putchar(NL);
+#endif /* AMIGA */
+#ifdef datageneral
+    if (c == CR) putchar(NL);
+#endif /* datageneral */
+#ifdef GEMDOS
+    if (c == CR) putchar(NL);
+#endif /* GEMDOS */
+#ifdef STRATUS
+    if (c == CR) putchar(NL);
+#endif /* STRATUS */
+}
+
+static VOID
+cmdchardel() {				/* Erase a character from the screen */
+    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 */
+    if (!dpx) return;
+    /* 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==CR) putchar((CHAR) NL);
+#endif /* OS2 */
+    if (timelimit)
+      fflush(stdout);
+}
+
+/* Return pointer to current position in command buffer. */
+
+char *
+cmpeek() {
+    return(np);
+}
+#endif /* NOICP */
+
+
+#ifdef NOICP
+#include "ckcdeb.h"
+#include "ckucmd.h"
+#include "ckcasc.h"
+#endif /* NOICP */
+
+/*  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
+xxesc(s) char **s; {			/* Expand backslash escapes */
+    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.
+    word  - the target string to look up in the table.
+    n     - the number of elements in the table.
+    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.  Maybe it could be improved
+  further with binary search or hash techniques but I doubt it since most
+  keyword tables are fairly short.
+*/
+
+#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
+lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; {
+
+    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);
+}
+
+/*
+  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
+xlookup(table,cmd,n,x) struct keytab table[]; char *cmd; int n, *x; {
+    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 *
+rlookup(table,n,x) struct keytab table[]; int n, x; {
+    int i;
+    for (i = 0; i < n; i++) {
+        if (table[i].kwval == x)
+	  return(table[i].kwd);
+    }
+    return(NULL);
+}
+
+#ifndef NOICP
+int
+cmdsquo(x) int x; {
+    quoting = x;
+    return(1);
+}
+
+int
+cmdgquo() {
+    return(quoting);
+}
+#endif /* NOICP */
diff --git a/ckermit-8.0.211/ckucmd.h b/ckermit-8.0.211/ckucmd.h
new file mode 100644
index 0000000..e994843
--- /dev/null
+++ b/ckermit-8.0.211/ckucmd.h
@@ -0,0 +1,302 @@
+/*  C K U C M D . H  --  Header file for Unix cmd package  */
+
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>
+  Columbia University Kermit Project, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 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 */
+
+#ifdef NORECALL
+#ifndef NOARROWKEYS
+#define NOARROWKEYS
+#endif /* NOARROWKEYS */
+#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
+#define CMDBL 4092
+#endif /* OS2 */
+#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;			/* Numeric result */
+    int kflags;				/* Keyword flags if any */
+} 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 */
+
+/* Function prototypes */
+
+_PROTOTYP( int xxesc, (char **) );
+_PROTOTYP( int cmrini, (int) );
+_PROTOTYP( VOID cmsetp, (char *) );
+_PROTOTYP( VOID cmsavp, (char [], int) );
+_PROTOTYP( char * cmgetp, () );
+_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 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, () );
+#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) );
+
+#ifdef DCMDBUF
+_PROTOTYP( int cmsetup, (void) );
+#endif /* DCMDBUF */
+
+#endif /* CKUCMD_H */
+
+/* End of ckucmd.h */
diff --git a/ckermit-8.0.211/ckucns.c b/ckermit-8.0.211/ckucns.c
new file mode 100644
index 0000000..296b106
--- /dev/null
+++ b/ckermit-8.0.211/ckucns.c
@@ -0,0 +1,2679 @@
+#include "ckcsym.h"
+char *connv = "CONNECT Command for UNIX:select(), 8.0.135, 29 Nov 2002";
+
+/*  C K U C N S  --  Terminal connection to remote system, for UNIX  */
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 <errno.h>			/* Error numbers */
+
+#ifndef NOTIMEH
+#include <time.h>			/* For FD_blah */
+#ifdef SYSTIMEH				/* (IRIX 5.3) */
+#include <sys/time.h>
+#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 */
+#ifndef NOCSETS
+#include "ckcxla.h"			/* Character set translation */
+#endif /* NOCSETS */
+
+#ifdef BEBOX
+#include <kernel/OS.h>
+#include <socket.h>
+#include <stdio.h>
+#endif /* BEBOX */
+
+#include <signal.h>			/* 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 <sys/timeb.h>
+#endif /* SYSTIMEBH */
+#endif /* NOSYSTIMEBH */
+#endif /* DCLTIMEVAL */
+#endif /* CKTIDLE */
+
+#ifndef SCO_OSR504
+#ifdef SELECT_H
+#include <sys/select.h>
+#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 */
+
+/* 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, 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,				/* <esc-char>Q was typed */
+  dohangup = 0,				/* <esc-char>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 */
+
+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 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 translated
+  into accented characters, 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 = NUL;
+	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 */
+
+/*  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
+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()
+  so a pointer to this function can be passed 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 */
+
+    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
+learnchar(c) int c; {			/* Learned script keyboard character */
+    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 == 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\r\n",sesfil,s);
+	}
+	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 <RESET> 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 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 */
+#ifdef XPRINT
+    escseq |= tt_print;
+#endif /* XPRINT */
+    inesc[0] = ES_NORMAL;		/* Initial state of recognizer */
+    inesc[1] = ES_NORMAL;
+    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);
+#ifndef NOSETKEY
+	    debug(F101,"CONNECT kmptr","",kmptr);
+#endif /* NOSETKEY */
+	}
+#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 == 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
+	    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(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 */
+	    /* debug(F101,"CONNECT c","",c); */
+	    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 == CR) {    /* Discard <NUL> of <CR><NUL> 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);
+		while (*s)
+		  ckcputc(*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] = 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. */
+			if (c == CR && tt_crd) { /* SET TERM CR-DISPLA CRLF? */
+			    ckcputc(c);	/* Yes, output CR */
+			    if (seslog && !sessft) logchar((char)c);
+			    c = LF;	/* and insert a linefeed */
+			}
+			if (dontprint)	{ /* Do transparent printing. */
+			    dontprint = 0;
+			    continue;
+			} else
+
+			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 */
+	    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 */
diff --git a/ckermit-8.0.211/ckucon.c b/ckermit-8.0.211/ckucon.c
new file mode 100644
index 0000000..bd866fe
--- /dev/null
+++ b/ckermit-8.0.211/ckucon.c
@@ -0,0 +1,2679 @@
+#include "ckcsym.h"
+
+char *connv = "CONNECT Command for UNIX:fork(), 8.0.114, 29 Nov 2002";
+
+/*  C K U C O N  --  Terminal connection to remote system, for UNIX  */
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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.
+*/
+#include "ckcdeb.h"			/* Common things first */
+
+#ifndef NOLOCAL
+
+#ifdef BEOSORBEBOX
+static double time_started = 0.0;
+#include <kernel/OS.h>
+_PROTOTYP( static long concld, (void *) );
+#else
+_PROTOTYP( static VOID concld, (void) );
+#endif /* BEOSORBEBOX */
+
+#ifdef NEXT
+#undef NSIG
+#include <sys/wait.h>			/* For wait() */
+#endif /* NEXT */
+
+#include <signal.h>			/* Signals */
+#include <errno.h>			/* Error numbers */
+
+#ifdef ZILOG				/* Longjumps */
+#include <setret.h>
+#else
+#include <setjmp.h>
+#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 */
+
+/* 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, 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,				/* <esc-char>Q was typed */
+  jbset = 0,				/* Flag whether jmp buf is set. */
+  dohangup = 0,				/* <esc-char>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 */
+  inesc = 0,				/* State of sequence recognizer */
+  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) 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)
+#else
+chkaes(c) char c;
+#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 == CR)		/* Discard <NUL> of <CR><NUL> */
+		  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); /* 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. */
+			if (c == CR && tt_crd) { /* SET TERM CR-DISPLA CRLF? */
+			    ckcputc(c);	/* Yes, output CR */
+			    if (seslog && !sessft)
+			      logchar((char)c);
+			    c = LF;	/* and insert a linefeed */
+			}
+			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);
+#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 == 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 == 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 */
diff --git a/ckermit-8.0.211/ckudia.c b/ckermit-8.0.211/ckudia.c
new file mode 100644
index 0000000..2f0fbfe
--- /dev/null
+++ b/ckermit-8.0.211/ckudia.c
@@ -0,0 +1,8249 @@
+#include "ckcsym.h"
+char *dialv = "Dial Command, 8.0.160, 29 Apr 2002";
+
+/*  C K U D I A	 --  Module for automatic modem dialing. */
+
+/*
+  Copyright (C) 1985, 2004,
+    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, Columbia University,
+  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 CKCPLM.DOC, the C-Kermit Program Logic
+  Manual, 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 <signal.h>
+#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 */
+#include <os2.h>
+#undef COMMENT
+#include "ckocon.h"
+#endif /* OS2ONLY */
+
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "cknwin.h"
+#include "ckntap.h"
+#endif /* NT */
+#ifdef OS2
+#include "ckowin.h"
+#endif /* OS2 */
+
+#ifndef ZILOG
+#ifdef NT
+#include <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#else
+#include <setret.h>
+#endif /* ZILOG */
+
+#include "ckcsig.h"        /* C-Kermit signal processing */
+
+#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. <sec>+++<sec>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 <parameter>" ("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 "<K%s\r>") */
+    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 */
+    "<D M%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 */
+    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
+dologdial(s) char *s; {
+    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
+ddinc(n) int n; {
+#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
+ttslow(s,millisec) char *s; int millisec; { /* Output s-l-o-w-l-y */
+#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)CR);
+	    scriptwrtbuf((USHORT)LF);
+	}
+#endif /* OS2 */
+    }
+    for (; *s; s++) {
+	ttoc(*s);
+#ifdef TCPSOCKET
+	if (*s == 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
+waitfor(s) char *s; {
+    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 == CR) conoc(LF);
+	    }
+	} while (x != c);
+    }
+}
+
+static int
+didweget(s,r) char *s, *r; {	/* Looks in string s for response r */
+    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 == CR) conoc(LF);		/* Echo CR as CRLF */
+    }
+}
+
+#ifndef NOSPL
+char *
+getdm(x) int x; {			/* Return dial modifier */
+    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
+dialfail(x) int x; {
+    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(F111,"dialfail()","lbuf",lbuf);
+         if (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 */
+		long strttime = time((long *)NULL);
+		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) {
+			diff = time((long *)NULL) - strttime;
+		    }
+		} 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] == CR) && (lbuf[n-1] == LF)) break;
+		    if ((lbuf[n] == LF) && (lbuf[n-1] == CR)) break;
+		}
+#ifndef MINIDIAL
+		else if (mymdmtyp == n_DIGITEL) {
+		    if (((lbuf[n] == CR) && (lbuf[n-1] == LF)) ||
+			((lbuf[n] == LF) && (lbuf[n-1] == CR)))
+		      break;
+		    else
+		      continue;
+		}
+#endif /* MINIDIAL */
+	    } else {			/* All others, break on CR or LF */
+		if ( lbuf[n] == 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] == CR) && (lbuf[n-1] == LF)) ||
+			    ((lbuf[n] == LF) && (lbuf[n-1] == 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
+ckdial(nbr) char *nbr;
+#else
+ckdial(nbr, x1, x2, fc, redial) char *nbr; int x1, x2, fc, redial;
+#endif /* OLD_DIAL */
+/* ckdial */ {
+#define ERMSGL 50
+    char errmsg[ERMSGL], *erp;		/* For error messages */
+    int n = F_TIME;
+    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 || n_PPI
+#endif /* MINIDIAL */
+	;
+
+    is_supra =
+#ifdef MINIDIAL
+      0
+#else
+      mymdmtyp == n_SUPRA || mymdmtyp == n_SUPRAX || 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;
+	if ((int)strlen(ttname) < (ERMSGL - 18)) /* safe, checked */
+	  sprintf(erp,"Sorry, can't open %s",ttname);
+	else
+	  sprintf(erp,"Sorry, can't open device");
+	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<CR> 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;
+#ifdef DEBUG
+    char * mdmmsg = "";
+#endif /* DEBUG */
+
+    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 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] == 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] == 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
+getok(n, strict) int n, strict; {
+    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 <suffix>
+    5x = CONNECT 1200 <suffix>
+    9x = CONNECT 2400 <suffix>
+   11x = CONNECT 4800 <suffix>
+   12x = CONNECT 9600 <suffix>
+  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 == 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 != 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 != 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     =   <listing name>"   */
+	debug(F110,"CALLID NAME",lbuf,0);
+	makestr(&callid_name,lbuf);
+    } else if (didweget(lbuf,"NMBR")) { /* Caller ID Number */
+	/* Format is "NMBR     =   <number>, '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     =   <tag><length><data><checksum>"   */
+	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, *p, 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 */
diff --git a/ckermit-8.0.211/ckufio.c b/ckermit-8.0.211/ckufio.c
new file mode 100644
index 0000000..298c48e
--- /dev/null
+++ b/ckermit-8.0.211/ckufio.c
@@ -0,0 +1,8310 @@
+/* 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, 8.0.200, 4 Mar 2004";
+#else
+#ifdef Plan9
+char *ckzv = "Plan 9 File support, 8.0.200, 4 Mar 2004";
+#else
+char *ckzv = "UNIX File support, 8.0.200, 4 Mar 2004";
+#endif /* Plan9 */
+#endif /* aegis */
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City,
+  and others noted in the comments below.  Note: CUCCA = Previous name of
+  Columbia University Academic Information Systems.
+
+  Copyright (C) 1985, 2004,
+    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 */
+
+#include <errno.h>
+#include <signal.h>
+
+#ifdef MINIX2
+#undef MINIX
+#undef CKSYSLOG
+#include <limits.h>
+#include <time.h>
+#define NOFILEH
+#endif /* MINIX2 */
+
+#ifdef MINIX
+#include <limits.h>
+#include <sys/types.h>
+#include <time.h>
+#else
+#ifdef POSIX
+#include <limits.h>
+#else
+#ifdef SVR3
+#include <limits.h>
+#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.  But this is subject to
+  change in future versions to conform to the normal OS/2 style.
+*/
+#ifndef DIRSEP
+#define DIRSEP       '/'
+#endif /* DIRSEP */
+#ifndef ISDIRSEP
+#define ISDIRSEP(c)  ((c)=='/')
+#endif /* ISDIRSEP */
+
+#ifdef SDIRENT
+#define DIRENT
+#endif /* SDIRENT */
+
+#ifdef XNDIR
+#include <sys/ndir.h>
+#else /* !XNDIR */
+#ifdef NDIR
+#include <ndir.h>
+#else /* !NDIR, !XNDIR */
+#ifdef RTU
+#include "/usr/lib/ndir.h"
+#else /* !RTU, !NDIR, !XNDIR */
+#ifdef DIRENT
+#ifdef SDIRENT
+#include <sys/dirent.h>
+#else
+#include <dirent.h>
+#endif /* SDIRENT */
+#else
+#include <sys/dir.h>
+#endif /* DIRENT */
+#endif /* RTU */
+#endif /* NDIR */
+#endif /* XNDIR */
+
+#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 <pwd.h>                        /* Password file for shell name */
+#ifdef CK_SRP
+#include <t_pwd.h>                      /* SRP Password file */
+#endif /* CK_SRP */
+
+#ifdef HPUX10_TRUSTED
+#include <hpsecurity.h>
+#include <prot.h>
+#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                        /* <sys/utime.h> if requested,  */
+#include <sys/utime.h>                  /* for extra fields required by */
+#else                                   /* 88Open spec. */
+#ifdef UTIMEH                           /* or <utime.h> if requested */
+#include <utime.h>                      /* (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, <OTHER>.  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 <sys/time.h>
+#include <sys/timeb.h>
+
+#else  /* Not BSD44 */
+
+#ifdef BSD4                             /* BSD 4.3 and below */
+#define TIMESTAMP                       /* Can do file dates */
+#include <time.h>                       /* Need this */
+#include <sys/timeb.h>                  /* Need this if really BSD */
+
+#else  /* Not BSD 4.3 and below */
+
+#ifdef SVORPOSIX                        /* System V or POSIX */
+#ifndef TIMESTAMP
+#define TIMESTAMP
+#endif /* TIMESTAMP */
+#include <time.h>
+
+/* 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 <time.h>
+#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 <stat.h>                       /* File status */
+#else
+#include <sys/stat.h>
+#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                         /* <sys/file.h> */
+#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 <sys/file.h>
+#endif /* NOFILEH */
+
+#ifndef is68k                           /* Whether to include <fcntl.h> */
+#ifndef BSD41                           /* All but a couple UNIXes have it. */
+#ifndef FT18
+#ifndef COHERENT
+#include <fcntl.h>
+#endif /* COHERENT */
+#endif /* FT18  */
+#endif /* BSD41 */
+#endif /* is68k */
+
+#ifdef COHERENT
+#ifdef _I386
+#include <fcntl.h>
+#else
+#include <sys/fcntl.h>
+#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 */
+#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) );
+
+/*
+  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 <pwd.h> 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 <shadow.h>
+#endif /* CK_SHADOW */
+#ifdef CK_PAM                           /* PAM... */
+#include <security/pam_appl.h>
+#ifndef PAM_SERVICE_TYPE                /* Defines which PAM service we are */
+#define PAM_SERVICE_TYPE "kermit"
+#endif /* PAM_SERVICE_TYPE */
+
+#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 */
+/*
+  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 */
+
+#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...  <param.h>, <mod.h>, <unistd.h>, <limits.h>, ...
+  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.
+*/
+#ifdef BSD44
+#include <sys/param.h>                  /* For MAXPATHLEN */
+#endif /* BSD44 */
+#ifdef COHERENT
+#include <sys/param.h>  /* 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 BIGBUFOK
+#define SSPACE 500000
+#else
+#define SSPACE 10000
+#endif /* BIGBUFOK */
+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 <stdio.h> */
+_PROTOTYP( FILE * fdopen, (int, char *) );
+#endif /* DCLFDOPEN */
+
+#ifdef DCLPOPEN
+/* popen() needs declaring because it's not declared in <stdio.h> */
+_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[MAXNAMLEN+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 <sys/syslog.h>
+#else  /* RTAIX */
+#include <syslog.h>
+#endif /* RTAIX */
+#endif /* CKSYSLOG */
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+
+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 <utmp.h> 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 <features.h>
+#include <sys/types.h>
+#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 <utmpx.h> */
+#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 <utmpx.h>
+#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 <utmp.h>
+#ifdef OSF50
+#undef __V40_OBJ_COMPAT
+#endif /* OSF50 */
+#endif /* HAVEUTMPX */
+#endif /* UTMPBUG */
+
+#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 */ {
+#ifdef HAVEUTMPX
+    struct utmpx ut;                    /* Needed for ut_host[] */
+#else
+    struct utmp ut;
+#endif /* HAVEUTMPX */
+    struct stat buf;
+    /* 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));
+        ckstrncpy(ut.ut_name, name, sizeof(ut.ut_name));
+#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
+        time(&ut.ut_time);
+#endif /* LINUX */
+#endif /* HAVEUTMPX */
+        if (write(wtmpfd, (char *)&ut, sizeof(struct utmp)) !=
+            sizeof(struct utmp)) {
+#ifndef NOFTRUNCATE
+#ifndef COHERENT
+            ftruncate(wtmpfd, buf.st_size); /* Error, undo any 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 maxnam = MAXNAMLEN;                 /* Available to the outside */
+int maxpath = MAXPATH;
+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;
+
+static long iflen = -1L;                /* 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
+getfullname(name) char * name; {
+    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
+zopeni(n,name) int n; char *name; {
+    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
+zopeno(n,name,zz,fcb)
+/* zopeno */  int n; char *name; struct zattr *zz; struct filinfo *fcb; {
+
+    char p[8];
+    int append = 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 DEBUG
+        if (n != ZDFILE)
+          debug(F101,"zopeno fp[n]=stdout","",fp[n]);
+#endif /* DEBUG */
+        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);
+    }
+    debug(F110,"zopeno fopen arg",p,0);
+    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);
+#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
+zclose(n) int n; {
+    int x = 0, x2 = 0;
+    extern long 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 %ld %s %c %s %c %c %s %s %d %s\n",
+                        ctime(&timenow),        /* date/time */
+                        gtimer(),               /* elapsed secs */
+                        s,                      /* peer name */
+                        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);
+                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
+zchin(n,c) int n; int *c; {
+    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 provided by the caller.
+  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
+zsinl(n,s,x) int n, x; char *s; {
+    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
+zxin(n,s,x) int n, x; char *s; {
+#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.  */
+
+int
+zsout(n,s) int n; char *s; {
+    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)
+      return(write(fileno(fp[n]),s,(int)strlen(s)));
+    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  */
+
+int
+zsoutl(n,s) int n; char *s; {
+    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));
+    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.  */
+
+int
+zsoutx(n,s,x) int n, x; char *s; {
+#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 */
+
+#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
+chkfn(n) int n; {
+    /* 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 issymlink 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 */
+
+long
+zgetfs(name) char *name; {
+    struct stat buf;
+    char fnam[CKMAXPATH+4];
+    long size = -1L;
+    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.
+*/
+long
+zchki(name) char *name; {
+    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 */
+
+    x = stat(s,&buf);
+    debug(F101,"STAT","",5);
+    if (x < 0) {
+        debug(F111,"zchki stat fails",s,errno);
+        return(-1);
+    }
+    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
+zchko(name) char *name; {
+    int i, x, itsadir = 0;
+    char *s;
+    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 */
+      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);
+
+    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);
+
+#ifdef SW_ACC_ID
+    debug(F100,"zchko swapping ids for access()","",0);
+    priv_on();
+#endif /* SW_ACC_ID */
+
+    x = access(s,W_OK);                 /* Check access of path. */
+
+#ifdef SW_ACC_ID
+    priv_off();
+    debug(F100,"zchko swapped ids restored","",0);
+#endif /* SW_ACC_ID */
+
+    if (x < 0)
+      debug(F111,"zchko access failed:",s,errno);
+    else
+      debug(F111,"zchko access ok:",s,x);
+    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
+zdelet(name) char *name; {
+    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
+zrtol(name,name2) char *name, *name2; {
+    nzrtol(name,name2,1,0,CKMAXPATH);
+}
+
+VOID
+nzrtol(name,name2,fncnv,fnrpath,max)
+    char *name, *name2; int fncnv, fnrpath, max;
+{ /* 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 MAXNAMLEN, 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 MAXNAMLEN","",MAXNAMLEN);
+        while (*p && n < CKMAXPATH) {   /* Copy name to new buffer */
+            if (++i > MAXNAMLEN) {      /* 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 < maxnam; 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
+zstrip(name,name2) char *name, **name2; {
+    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
+zltor(name,name2) char *name, *name2; {
+    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
+nzltor(name,name2,fncnv,fnspath,max)
+    char *name, *name2; int fncnv, fnspath, max;
+{ /* 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
+zchdir(dirnam) char *dirnam; {
+    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
+  <unistd.h>.  See the section for including <unistd.h> 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
+zxcmd(filnum,comand) int filnum; char *comand; {
+    int out;
+    int pipes[2];
+    extern int kactive;                 /* From ckcpro.w 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
+zclosf(filnum) int filnum; {
+    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.
+*/
+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
+initspace(resarry,len) char * resarry[]; int len; {
+#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
+zsetfil(n, fc) int n, fc; {
+#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
+zxpand(fnarg) char *fnarg; {
+    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",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.
+*/
+    if (!diractive && haveonedir) {
+#ifdef COMMENT
+	fcount = (mtchs == NULL &&
+		  (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
+	  ? 0 : 1;
+#else
+	fcount = 0;
+	if (!mtchs) {
+	    mtchs = (char **)malloc(maxnames * sizeof(*mtchs));
+	    if (mtchs)
+	      fcount = 1;
+	    if (!fcount)
+	      return(nxpand = fcount);
+	}
+#endif /* COMMENT */
+	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(F110,"zxpand haveonedir A2",*mtchptr,0);
+	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
+nzxpand(s,flags) char * s; int flags; {
+    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
+znext(fn) char *fn; {
+    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, long n)
+#else
+zchkspa(f,n) char *f; long 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 "<oldname>.~<n>~", where <oldname> is argument name
+  (fn), and <n> 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 <fn> 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
+znewn(fn,s) char *fn, **s; {
+    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 = MAXNAMLEN;                /* 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.~<d+1>~" */
+        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
+zrename(old,new) char *old, *new; {
+    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
+zcopy(source,destination) char *source, *destination; {
+    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
+zsetperm(f,code) char * f; int code; {
+    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 *
+zgperm(f) char *f; {
+    extern int diractive;
+    int x; char *s = (char *)xlperms;
+    struct stat buf;
+    debug(F110,"zgperm",f,0);
+    if (!f) return("----------");
+    if (!*f) return("----------");
+
+#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 *
+ziperm(f) char * f; {
+    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);
+
+    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
+zsattr(xx) struct zattr *xx; {
+    long k; int x;
+    struct stat buf;
+
+    k = iflen % 1024L;                  /* File length in K */
+    if (k != 0L) k = 1L;
+    xx->lengthk = (iflen / 1024L) + 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;
+    struct tm * localtime();
+    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 *
+zfcdat(name) char *name; {
+#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
+zstrdt(date,len) char * date; int len; {
+#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
+    extern int ftime();
+#endif /* M_XENIX */
+#endif /* M_UNIX */
+    extern struct tm * localtime();
+
+    /* 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
+    long tmx, days;
+#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
+            tmx += timezone;
+#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 *
+zlocaltime(gmtstring) char * gmtstring; {
+#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
+    extern int ftime();
+#endif /* M_XENIX */
+#endif /* M_UNIX */
+    extern struct tm * localtime();
+
+    /* 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
+    long tmx, days;
+#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.
+ 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
+zstime(f,yy,x)
+    char *f; struct zattr *yy; int x;
+/* 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
+    extern int utimes();
+#else
+    extern int utime();
+#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);
+
+    debug(F110,"zstime",f,0);
+    debug(F111,"zstime date",yy->date.val,yy->date.len);
+
+#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;
+#ifdef DEBUG
+        char obuf[24];
+        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 */
+
+#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);
+            g = xunchar(*(yy->gprotect.val)); /* Decode generic protection */
+            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
+zprint(p,f) char *p; char *f; {         /* Print file f with options p */
+    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
+shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
+    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 *
+splitpath(p) char *p; {
+    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 < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
+              cur -> npart[i] = *p++;
+            cur -> npart[i] = '\0';     /* end this segment */
+            if (i >= MAXNAMLEN)
+              while (*p && *p != '/' && *p != bslash)
+                p++;
+        }
+        if (*p == '/') p++;
+#else
+        /* General case (UNIX) */
+        for (i = 0; i < MAXNAMLEN && !ISDIRSEP(*p) && *p != '\0'; i++) {
+            cur -> npart[i] = *p++;
+        }
+
+        cur -> npart[i] = '\0';         /* End this path segment */
+        if (i >= MAXNAMLEN)
+          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
+fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
+    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
+traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
+
+/* 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, <dirent.h> */
+#define OPENDIR
+    DIR *fd, *opendir();
+    struct dirent *dirbuf;
+    struct dirent *readdir();
+#else /* !DIRENT */
+#ifdef LONGFN                           /* Old way, <dir.h> with opendir() */
+#define OPENDIR
+    DIR *fd, *opendir();
+    struct direct *dirbuf;
+#else /* !LONGFN */
+    int fd;                             /* Old way, <dir.h> 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[MAXNAMLEN+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 = iswild(pl -> npart);
+
+    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))
+#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,
+                  MAXNAMLEN
+                  );
+          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<Esc>" */
+	      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 <star>/<star>.txt lists every file in * and does not even open up the
+  subdirectories.  However, "dir /rec <star>/<star>.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
+addresult(str,itsadir) char *str; int itsadir; {
+    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) );
+
+    if (ruid != -1)
+      return(realname);
+
+    ruid = real_uid();                  /* get our uid */
+
+  /* how about $USER or $LOGNAME? */
+    if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
+        ckstrncpy(envname, c, 255);
+        if ((p = getpwnam(envname)) != NULL) {
+            if (p->pw_uid == ruid) {    /* get passwd entry for envname */
+                ckstrncpy(realname, envname, UIDBUFLEN); /* uid's are same */
+                return(realname);
+            }
+        }
+    }
+
+  /* can we use loginname() ? */
+
+    if ((c =  getlogin()) != NULL) {    /* name from utmp file */
+        ckstrncpy (loginname, c, UIDBUFLEN);
+        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 */
+        realname[0] = '\0';             /* no user name */
+        ruid = -1;
+        return(NULL);
+    }
+    ckstrncpy(realname, p->pw_name, UIDBUFLEN);
+    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 *
+tilde_expand(dirname) char *dirname; {
+#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 */
+      return(dirname);
+    if (!strcmp(olddir,dirname)) {      /* Same as last time */
+      return(oldrealdir);               /* so return old answer. */
+    } else {
+        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 */
+        if (i == 1) {                   /* if just a "~" */
+#ifdef IKSD
+            if (inserver)
+              user = getpwnam(uidbuf);  /* Get info on current user */
+            else
+#endif /* IKSD */
+            {
+                char * p = whoami();
+                if (p)
+		  user = getpwnam(p);
+                else
+		  user = NULL;
+            }
+        } else {
+            user = getpwnam(&temp[1]);  /* otherwise on the specified user */
+        }
+    }
+    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
+zsyscmd(s) char *s; {
+#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
+z_exec(p,s,t) char * p, ** s; int t; {  /* Overlay ourselves with "p s..." */
+#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
+zshcmd(s) char *s; {
+    PID_T pid;
+
+#ifdef NOPUSH
+    return(0);
+#else
+    if (nopush) return(-1);
+    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);
+        if (shpath == NULL) {
+            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",shpath,0);
+        }
+#endif /* COMMENT */
+#endif /* aegis */
+        shptr = shname = shpath;
+        while (*shptr != '\0')
+          if (*shptr++ == DIRSEP)
+            shname = shptr;
+	restorsigs();			/* Restore ignored signals */
+	debug(F110,"zshcmd shname",shname,0);
+        if (s == NULL || *s == '\0') {  /* Interactive shell requested? */
+            execl(shpath,shname,"-i",NULL); /* Yes, do that */
+        } else {                        /* Otherwise, */
+            execl(shpath,shname,"-c",s,NULL); /* exec the given command */
+        }                               /* If execl() failed, */
+        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... */
+
+#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 if 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
+iswild(filespec) char *filespec; {
+    char c, *p, *f; int x;
+    int quo = 0;
+    if (!filespec)
+      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(MAXNAMLEN + 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
+isdir(s) char *s; {
+    int x, needrlink = 0, islink = 0;
+    struct stat statbuf;
+    char fnam[CKMAXPATH+4];
+
+    if (!s) return(0);
+    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
+zmkdir(path) char *path; {
+    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
+zrmdir(path) char *path; {
+#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:
+    Long int, 0-based, indicating desired position.
+   Returns:
+    0 on success.
+   -1 on failure.
+*/
+#ifndef NORESEND
+int
+#ifdef CK_ANSIC
+zfseek(long pos)
+#else
+zfseek(pos) long pos;
+#endif /* CK_ANSIC */
+/* zfseek */ {
+    zincnt = -1;                        /* Must empty the input buffer */
+    debug(F101,"zfseek","",pos);
+    return(fseek(fp[ZIFILE], pos, 0)?-1:0);
+}
+#endif /* NORESEND */
+
+/*  Z F N Q F P  --  Convert filename to fully qualified absolute pathname */
+
+static struct zfnfp fnfp = { 0, NULL, NULL };
+
+struct zfnfp *
+zfnqfp(fname, buflen, buf)  char * fname; int buflen; char * buf; {
+    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
+zcmpfn(s1,s2) char * s1, * s2; {
+    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
+zsetroot(s) char * s; {			/* Sets the root */
+    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 *
+zgetroot() {				/* Returns the root */
+    if (!ckrootset)
+      return(NULL);
+    return((char *)ckroot);
+}
+
+int
+zinroot(s) char * s; {			/* Checks if file s is in the root */
+    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 *
+sgetsave(s) char *s; {
+    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 *
+sgetpwnam(name) char *name; {
+    static struct passwd save;
+    register struct passwd *p;
+#ifdef CK_SHADOW
+    register struct spwd *sp;
+#endif /* CK_SHADOW */
+    char *sgetsave();
+
+#ifdef HPUX10_TRUSTED
+    struct pr_passwd *pr;
+#endif /* HPUX10_TRUSTED */
+
+#ifdef CK_SHADOW
+    sp = getspnam(name);
+    debug(F111,"sgetpwnam","getspnam()",sp);
+    if (sp == NULL)
+      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);
+        free(save.pw_gecos);
+        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 */
+    save.pw_gecos = sgetsave(p->pw_gecos);
+    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
+zvuser(name) char *name; {
+    register char *cp = NULL;
+    int x;
+    char *shell;
+#ifdef GETUSERSHELL
+    char *getusershell();
+#endif /* GETUSERSHELL */
+
+#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 (strcmp(cp, shell) == 0)
+              break;
+        }
+        debug(F100,"zvuser endusershell 1","",0);
+        endusershell();
+        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
+checkuser(name) char *name; {
+    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 */
+
+int
+zvpass(p) char *p; {
+    char *xpasswd, *salt;
+    char * dir = NULL;
+#ifdef CK_PAM
+    int pam_status;
+    const char * reply = NULL;
+#endif /* CK_PAM */
+
+    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);
+        if (*p)
+	  pam_pw = p;
+        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 */
+    }
+
+    (VOID) setgid((GID_T)pw->pw_gid);   /* Set group ID */
+
+#ifndef NOINITGROUPS
+    (VOID) 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 */
diff --git a/ckermit-8.0.211/ckuins.txt b/ckermit-8.0.211/ckuins.txt
new file mode 100644
index 0000000..86448a3
--- /dev/null
+++ b/ckermit-8.0.211/ckuins.txt
@@ -0,0 +1,3519 @@
+
+C-Kermit 8.0 Unix Installation Instructions
+
+   [ [1]Contents ] [ [2]C-Kermit ] [ [3]Kermit Home ]
+
+   Frank da Cruz
+   The Kermit Project
+   Columbia University
+
+      As of C-Kermit version: 8.0.211, 10 April 2004
+      This file last updated: Tue Apr 13 10:14:33 2004 (New York City
+   time)
+
+   IF YOU ARE READING A PLAIN-TEXT version of this document, note that
+   this file is a plain-text dump of a Web page. You can visit the
+   original (and possibly more up-to-date) Web page here:
+
+[4]http://www.columbia.edu/kermit/ckuins.html
+  __________________________________________________________________________
+
+CONTENTS
+
+     [5]OVERVIEW
+
+    1. [6]INTERNET QUICK START
+    2. [7]INSTALLING FROM PACKAGES
+    3. [8]INSTALLING PREBUILT BINARIES
+    4. [9]BUILDING FROM SOURCE CODE
+    5. [10]INSTALLING THE KERMIT FILES
+    6. [11]INSTALLING UNIX C-KERMIT FROM DOS-FORMAT DISKETTES
+    7. [12]CHECKING THE RESULTS
+    8. [13]REDUCING THE SIZE OF THE EXECUTABLE PROGRAM IMAGE
+    9. [14]UNIX VERSIONS
+   10. [15]DIALING OUT AND COORDINATING WITH UUCP
+   11. [16]RUNNING UNIX C-KERMIT SETUID OR SETGID
+   12. [17]CONFIGURING UNIX WORKSTATIONS
+   13. [18]BIZARRE BEHAVIOR AT RUNTIME
+   14. [19]CRASHES AND CORE DUMPS
+   15. [20]SYSLOGGING
+   16. [21]BUILDING SECURE VERSIONS OF C-KERMIT 8.0
+   17. [22]INSTALLING C-KERMIT AS AN SSH SERVER SUBSYSTEM
+  __________________________________________________________________________
+
+OVERVIEW
+
+   [ [23]Top ] [ [24]Contents ] [ [25]Next ]
+
+     WARNING: This document contains notes that have been accumulating
+     since the early 1980s. Many of the products and Unix versions
+     mentioned here have not been heard of in a long while, but that
+     does not necessarily mean they are not still running in some
+     obscure nook. 
+
+   This file contains Unix-specific information. A lot of it. Unlike most
+   other packages, C-Kermit tries very hard to be portable to every Unix
+   variety (and every release of each one) known to exist, including many
+   that are quite old, as well as to other platforms like VMS, AOS/VS,
+   VOS, OS-9, the BeBox, the Amiga, etc.
+
+   Since C-Kermit gets so deeply into the file system, i/o system, and
+   other areas that differ radically from one Unix platform to the next,
+   this means that a lot can go wrong when you try to install C-Kermit on
+   (for example) a new release of a particular variety of Unix, in which
+   certain things might have changed that C-Kermit depended upon.
+
+   This file concentrates on installation. For a description of general
+   configuration options for C-Kermit, please read the [26]Configurations
+   Options document. For troubleshooting after installation, see the
+   [27]General Hints and Tips and [28]Unix-Specific Hints and Tips
+   documents. The latter, in particular, contains lots of information on
+   lots of specific Unix platforms. If you want to work on the source
+   code, see the [29]C-Kermit Program Logic Manual
+
+   You may install C-Kermit:
+
+     * From an "[30]install package", if one is available.
+     * As a [31]prebuilt binary, if available, plus accompanying text
+       files.
+     * By building from [32]source code.
+  __________________________________________________________________________
+
+1. INTERNET QUICK START
+
+   [ [33]Top ] [ [34]Contents ] [ [35]Next ] [ [36]Previous ]
+
+   If your Unix computer is on the Internet and it has a C compiler,
+   here's how to download, build, and install C-Kermit directly from the
+   "tarballs" or Zip archives:
+
+    1. Make a fresh directory and cd to it.
+    2. Download the C-Kermit source code:
+       [37]ftp://kermit.columbia.edu/kermit/archives/cku211.tar.Z
+       (compress format) or
+       [38]ftp://kermit.columbia.edu/kermit/archives/cku211.tar.gz
+       (gunzip format).
+    3. Uncompress the compressed tar file with "uncompress" or "gunzip",
+       according to which type of compressed file you downloaded. (If you
+       don't understand this, you could download a (much larger)
+       uncompressed tar archive directly:
+       [39]ftp://kermit.columbia.edu/kermit/archives/cku211.tar
+    4. Now type "tar xvf cku211.tar" to unpack the individual files from
+       the tar archive.
+    5. Type "rm cku211.tar" to get rid of the tar archive, which is no
+       longer needed.
+    6. Read the comments at the top of the makefile to find out which
+       target to use and then type the appropriate "make" command, such
+       as "make linux", "make solaris8", etc.
+    7. This produces a binary in your current directory called "wermit".
+       Start it by typing "./wermit" and [40]try it out to make sure it
+       works. Then read [41]Section 5 for how to install it, or simply
+       copy the wermit binary to the desired public directory, rename it
+       to kermit, and give it the needed permissions (and, if it is going
+       to be used to dial out, give it the same group and owner and
+       permissions as the cu, tip, or minicom program).
+
+   For secure installations, see [42]Sections 5 and [43]16.
+  __________________________________________________________________________
+
+2. INSTALLING FROM PACKAGES
+
+   [ [44]Top ] [ [45]Contents ] [ [46]Next ] [ [47]Previous ]
+
+   Various Unix varieties -- Linux, Solaris, AIX, etc -- now incorporate
+   the idea of "install packages", and many users expect to find all new
+   applications in this format. A selection of install packages might be
+   available for any given release of C-Kermit, but there is a tradeoff
+   between convenience and safety. Unix presents several notable problems
+   to the builder of install packages:
+
+    a. Since C-Kermit is portable to many non-Unix platforms (VMS, VOS,
+       AOS/VS, etc), some of the files in the C-Kermit distribution do
+       not fit into the Unix application model. In particular, C-Kermit
+       includes some plain text files (described in [48]Section 5) and
+       Unix has no standard place to put such files. Typical Unix package
+       managers do not allow for them. Where should they go, and how will
+       the user know where to find them?
+    b. Installation of any program that will be used to make modem calls
+       requires some important decisions from the installer regarding
+       security and privilege.
+
+   Item (b) is discussed at length in [49]Sections 10 and [50]11 of this
+   document, but the package-related aspects are also given here. The
+   basic problem is that Unix dialout devices and the UUCP "lock files"
+   that regulate contention for them (described in [51]Section 10) are
+   usually protected against "world". Therefore, the install procedure
+   must either run as root in order to give the Kermit binary the
+   required permissions, group, and/or owner, or else the dialout devices
+   and associated directories must be open for group or world reading and
+   writing. Otherwise, the Kermit program just installed WILL NOT WORK
+   for dialing out.
+
+   Thus, a well-crafted installation procedure should present the options
+   and allow the installer to choose the method, if any, for regulating
+   access to the dialout devices:
+
+    a. Check the permissions of the lockfile directory and the dialout
+       devices. If they do not allow group or world R/W access, then:
+    b. "Your UUCP lockfile directory and/or dialout devices require
+       privilege to access. You must either change their permissions or
+       install Kermit with privileges."
+    c. "If you wish to install Kermit with privileges, it will be given
+       the same owner, group, and permissions as the cu program so it can
+       use the dialout devices."
+    d. If they choose (c) but the user is not root, give a message that
+       the install procedure can be run only by root and then quit.
+
+   It should go without saying, of course, that any binaries that are to
+   be included in an install package should be built fresh on the exact
+   platform (e.g. Red Hat 8.0 on Intel) for which the package is
+   targeted; prebuilt binaries ([52]next section) from other sites are
+   likely to have library mismatches. [53]CLICK HERE for more about
+   building C-Kermit install packages.
+
+   The Kermit Project does not have the resources or the expertise to
+   make install packages for every platform. Most install packages,
+   therefore, are contributed by others, and they do not necessarily
+   follow the guidelines given above. Pay attention to what they do.
+
+   If you are an end user who has obtained a C-Kermit install package for
+   a particular platform, you should be aware that some additional steps
+   might needed if you want to use Kermit to dial out. Read [54]Section
+   10 for details.
+  __________________________________________________________________________
+
+3. INSTALLING PREBUILT BINARIES
+
+   [ [55]Top ] [ [56]Contents ] [ [57]Next ] [ [58]Previous ]
+
+   Hundreds of prebuilt C-Kermit binaries are available on the CDROM in
+   the BINARY tree [NOTE: The C-Kermit CDROM is still for version 7.0],
+   and at our ftp site in the [59]kermit/bin area (with names starting
+   with "ck"), also accessible on the [60]C-Kermit website. To install a
+   prebuilt binary:
+
+    a. Rename the binary to "wermit".
+    b. Make sure it works; some tests are suggested in [61]Section 7.
+    c. Follow steps (b) through (e) in [62]Section 4.
+    d. Install related files as described in [63]Section 5.
+
+   But first... Please heed the following cautions:
+
+    a. If you pick the wrong binary, it won't work (or worse).
+    b. Even when you pick the appropriate binary, it still might not work
+       due to shared-library mismatches, etc. (see [64]Section 4.0).
+    c. Don't expect a binary built on or for version n of your OS to work
+       on version n - x (where x > 0). However, it is usually safe to run
+       a binary built on (or for) an older OS release on a newer one.
+
+   Therefore, it is better to build your own binary from source code
+   ([65]next section) if you can. But since it is increasingly for Unix
+   systems (not to mention VMS and other OS's) to be delivered without C
+   compilers, it is often impractical. In such cases, try the most
+   appropriate prebuilt binary or binaries, and if none of them work,
+   [66]contact us and we'll see what we can do to help.
+  __________________________________________________________________________
+
+4. BUILDING FROM SOURCE CODE
+
+   [ [67]Top ] [ [68]Contents ] [ [69]Next ] [ [70]Previous ]
+
+   Also see: [71]Section 8 and [72]Section 9.
+
+   C-Kermit is designed to be built and used on as many platforms as
+   possible: Unix and non-Unix, old and new (and ancient), ANSI C and
+   K&R. The Unix version does not use or depend on any external tools for
+   building except the "make" utility, the C compiler, and the linker. It
+   does not use any automated configuration tools such as configure,
+   autoconf, automake, libtool, etc. Everything in C-Kermit has been
+   built by hand based on direct experience or reports or contributions
+   from users of each platform.
+
+   The [73]C-Kermit makefile contains the rules for building the program
+   for each of the hundreds of different kinds of Unix systems that
+   C-Kermit attempts to support. It covers all Unix variations since
+   about 1980 -- pretty much everything after Unix V6. Separate makefiles
+   are used for [74]Plan 9 and [75]2.x BSD.
+
+   Prerequisites:
+
+     * The C compiler, linker, and make program must be installed.
+     * The C libraries and header files must be installed (*).
+     * The C-Kermit source code and makefile in your current directory.
+     * The C-Kermit text files ([76]Section 5) in your current directory.
+
+     * This is becoming problematic in this new age of "selective
+       installs" e.g. of Linux packages. C-Kermit builds will often fail
+       because replying "no" to some obscure Linux installation option
+       will result in missing libraries or header files. Ditto on
+       platforms like AIX and Solaris that don't come with C compilers,
+       and then later have gcc installed, but are still missing crucial
+       libraries, like libm (math).
+
+   Plus:
+
+     * For TCP/IP networking support, the sockets library and related
+       header files must be installed.
+     * The math library for floating-point arithmetic support (can be
+       deselected by adding -DNOFLOAT to CFLAGS and removing -lm from
+       LIBS).
+     * Many and varied security libraries for building a secure version
+       (Kerberos, SSL/TLS, SRP, Zlib,...) These are required only if you
+       select a secure target.
+     * For the curses-based fullscreen file-ransfer display, the curses
+       or ncurses header file(s) and library, and probably also the
+       termcap and/or termlib library. Note that the names and locations
+       of these files and libraries are likely to change capriciously
+       with every new release of your Unix product. If you discover that
+       the C-Kermit build procedure fails because your curses and/or
+       termxxx headers or libraries are not named or located as expected,
+       please [77]let us know. In the meantime, work around by installing
+       symlinks.
+     * IMPORTANT: Modern Linux distributions might give you the choice
+       during installation of whether to install the "ncurses development
+       package" (perhaps called "ncurses-devel"). If you did not install
+       it, you won't be able to build C-Kermit with curses support
+       included. In this case, either go back and install ncurses, or
+       else choose (or create) a non-curses makefile target for your
+       platform. To install the ncurses developers tools in Red Hat
+       Linux, do:
+
+mount redhat cdrom
+goto RedHat/RPMS
+rpm -ivh ncurses-devel*.rpm
+or to have the exact name ls ncurse* and load as
+rpm -ivh filename
+then leave the cdrom and unmount it.
+
+     * In AIX you might have to go back and install any or all of:
+
+bos.adt.base
+bos.adt.include
+bos.adt.lib
+bos.adt.libm
+bos.adt.utils
+
+       from the first installation CD.
+
+   The makefile might need to be renamed from ckuker.mak to makefile.
+   Directions:
+
+    a. Type "make xxx" where xxx is the name of the makefile target most
+       appropriate to your platform, e.g. "make linux", "make aix43",
+       etc. Read the [78]comments at the top of the makefile for a
+       complete list of available targets (it's a long list).
+    b. Test the resulting 'wermit' file (see [79]Section 7 for
+       suggestions). If it's OK, proceed; otherwise [80]notify us.
+
+     NOTE: steps (c) through (e) can be accomplished using the
+     [81]makefile 'install' target as described in [82]Section 5.4. 
+    c. Rename the 'wermit' file to 'kermit', copy it to the desired
+       binary directory (such as /usr/local/bin or /opt/something), and
+       if it is to be used for dialing out, give it the same owner,
+       group, and permissions as the 'cu' program (IMPORTANT: read
+       [83]Sections 10 and [84]11 for details).
+    d. Install the man page, ckuker.nr, with your other man pages.
+    e. Install the accompanying text files (see [85]Section 5).
+    f. If you want C-Kermit to also offer a Telnet command-line
+       personality, make a symbolic link as follows:
+
+cd directory-where-kermit-binary-is
+ln -s kermit telnet
+
+       If you want C-Kermit to be the default Telnet client, make sure
+       the directory in which you created the symlink is in the PATH
+       ahead of the where the regular Telnet client is.
+    g. If you want C-Kermit to also offer an FTP command-line
+       personality, make a symlink called "ftp" as in (f).
+    h. If you want C-Kermit to also offer an FTTP command-line
+       personality, make a symlink called "http" as in (f).
+    i. If you want to offer an Internet Kermit Service, follow the
+       directions in the [86]IKSD Administrator's Guide.
+    ________________________________________________________________________
+
+  4.0. Special Considerations for C-Kermit 8.0
+
+   [ [87]Top ] [ [88]Contents ] [ [89]Next ]
+
+   Also see: [90]C-Kermit Configuration Options
+
+   SECTION CONTENTS
+
+4.1. [91]The Unix Makefile
+4.2. [92]The C-Kermit Initialization File
+4.3. [93]The 2.x BSD Makefile
+4.4. [94]The Plan 9 Makefile
+4.5. [95]Makefile Failures
+
+   (Also see the [96]Configurations Options document, [97]Section 8).
+
+   Lots of new features have been added in versions 7.0 and 8.0 that
+   require access to new symbols, APIs, libraries, etc, and this will no
+   doubt cause problems in compiling, linking, or execution on platforms
+   where 6.0 and earlier built without incident. This section contains
+   what we know as of the date of this file.
+
+   The first category concerns the new Kermit Service Daemon (IKSD; see
+   the [98]IKSD Administrator's Guide for details):
+
+   The wtmp File
+          When C-Kermit is started as an IKSD (under inetd), it makes
+          syslog and wtmp entries, and also keeps its own ftpd-like log.
+          The code assumes the wtmp log is /var/log/wtmp on Linux and
+          /usr/adm/wtmp elsewhere. No doubt this assumption will need
+          adjustment. Use -DWTMPFILE=path to override at compile time
+          (there is also a runtime override). See [99]iksd.html for
+          details.
+
+   UTMP, utsname(), etc
+          C-Kermit 7.0 gets as much info as it can about its job --
+          mainly for IKSD logging -- from utmp. But of course utmp
+          formats and fields differ, and for that matter, there can be
+          two different header files, <utmp.h> and <utmpx.h>. Look for
+          HAVEUTMPX and HAVEUTHOST in [100]ckufio.c and let me know of
+          any needed adjustments.
+
+   Password lookup
+          IKSD needs to authenticate incoming users against the password
+          list. In some cases, this requires the addition of -lcrypt
+          (e.g. in Unixware 2.x). In most others, the crypt functions are
+          in the regular C library. If you get "crypt" as an unresolved
+          symbol at link time, add -lcrypt to LIBS. If your site has
+          local replacement libraries for authentication, you might need
+          a special LIBS clause such as "LIBS=-L/usr/local/lib -lpwent".
+
+          These days most Unix systems take advantage of shadow password
+          files or Plugable Authentication Modules (PAM). If your system
+          uses shadow passwords you must add -DCK_SHADOW to the CFLAGS
+          list. If your system requires PAM you must add -DCK_PAM to the
+          CFLAGS and -lpam -ldl to LIBS.
+
+   getusershell()
+          This is called by the IKSD at login time to see if a user has
+          been "turned off". But many Unix platforms lack this function.
+          In that case, you will get unresolved symbol reports at link
+          time for _getusershell, _endusershell; to work around, add
+          -DNOGETUSERSHELL.
+
+   initgroups()
+          This is called by IKSD after successful authentication. But
+          some platforms do not have this function, so obviously it can't
+          be called there, in which case add -DNOINITGROUPS.
+
+   setreuid(), setreuid(), setregid() not found or "deprecated"
+          Find out what your Unix variety wants you to use instead, and
+          make appropriate substitutions in routine zvpass(), module
+          [101]ckufio.c, and [102]let us know.
+
+   printf()
+          IKSD installs a printf() substitute to allow redirection of
+          printf-like output to the connection. However, this can
+          conflict with some curses libraries. In this case, separate
+          binaries must be built for IKSD and non-IKSD use.
+
+   If you encounter difficulties with any of the above, and you are not
+   interested in running C-Kermit as an IKSD, then simply add NOIKSD to
+   CFLAGS and rebuild. Example:
+
+make sco286
+(get lots of errors)
+make clean
+make sco286 "KFLAGS=-DNOIKSD"
+
+   Some non-IKSD things to watch out for:
+
+   Return type of main()
+          The main() routine is in [103]ckcmai.c. If you get complaints
+          about "main: return type is not blah", define MAINTYPE on the
+          CC command line, e.g.:
+
+make xxx "KFLAGS=-DMAINTYPE=blah
+
+          (where blah is int, long, or whatever). If the complaint is
+          "Attempt to return a value from a function of type void" then
+          add -DMAINISVOID:
+
+make xxx "KFLAGS=-DMAINISVOID=blah
+
+   DNS Service Records
+          This feature allows a remote host to redirect C-Kermit to the
+          appropriate socket for the requested service; e.g. if C-Kermit
+          requests service "telnet" and the host offers Telnet service on
+          port 999 rather than the customary port 23. If you get
+          compile-time complaints about not being able to find
+          <resolv.h>, <netdb.h>, or <arpa/nameser.h>, add -DNO_DNS_SRV to
+          CFLAGS. If you get link-time complaints about unresolved
+          symbols res_search or dn_expand, try adding -lresolve to LIBS.
+
+   \v(ipaddress)
+          If "echo \v(ipaddress)" shows an empty string rather than your
+          local IP address, add -DCKGHNLHOST to CFLAGS and rebuild.
+
+   <sys/wait.h>
+          If this file can't be found at compile time, add -DNOREDIRECT
+          to CFLAGS. This disables the REDIRECT and PIPE commands and
+          anything else that needs the wait() system service.
+
+   syslog()
+          C-Kermit can now write syslog records. Some older platforms
+          might not have the syslog facility. In that case, add
+          -DNOSYSLOG. Others might have it, but require addition of
+          -lsocket to LIBS (SCO OSR5 is an example). See [104]Section 15.
+
+   putenv()
+          If "_putenv" comes up as an undefined symbol, add -DNOPUTENV to
+          CFLAGS and rebuild.
+
+   "Passing arg1 of 'time' from incompatible pointer"
+          This is a mess. See the mass of #ifdefs in the appropriate
+          module, [105]ckutio.c or [106]ckufio.c.
+
+   gettimeofday()
+          Wrong number of arguments. On most platforms, gettimeofday()
+          takes two arguments, but on a handful of others (e.g. Motorola
+          System V/88 V4, SNI Reliant UNIX 5.43, etc) it takes one. If
+          your version of gettimeofday() is being called with two args
+          but wants one, add -DGTODONEARG.
+
+   "Assignment makes pointer from integer without a cast"
+          This warning might appear in [107]ckutio.c or [108]ckufio.c.
+          (or elsewhere), and usually can be traced to the use of a
+          system or library function that returns a pointer but that is
+          not declared in the system header files even though it should
+          be. Several functions are commonly associated with this error:
+
+          + getcwd(): Add -DDCLGETCWD to CFLAGS and rebuild.
+          + popen() : Add -DDCLPOPEN to CFLAGS and rebuild.
+          + fdopen(): Add -DDCLFDOPEN to CFLAGS and rebuild.
+
+   "Operands of = have incompatible types"
+   "Incompatible types in assignment"
+          If this comes from [109]ckcnet.c and comes from a statement
+          involving inet_addr(), try adding -DINADDRX to CFLAGS. If that
+          doesn't help, then try adding -DNOMHHOST.
+
+   Complaints about args to get/setsockopt(), getpeername(),
+          getsockname()
+          These are all in [110]ckcnet.c. Different platforms and OS's
+          and versions of the same OS change this all the time: int,
+          size_t, unsigned long, etc. All the affected variables are
+          declared according to #ifdefs within ckcnet.c, so find the
+          declarations and adjust the #ifdefs accordingly.
+
+   size_t
+          In case of complaints about "unknown type size_t", add
+          -DSIZE_T=int (or other appropriate type) to CFLAGS.
+
+   'tz' undefined
+   Use of undefined enum/struct/union 'timezone'
+          Left of 'tv_sec' specifies undefined struct/union 'timeval' And
+          similar complaints in [111]ckutio.c: Add -DNOGFTIMER and/or
+          -DNOTIMEVAL.
+
+   Symlinks
+          The new built-in DIRECTORY command should show symlinks like
+          "ls -l" does. If it does not, check to see if your platform has
+          the lstat() and readlink() functions. If so, add -DUSE_LSTAT
+          and -DCKSYMLINK to CFLAGS and rebuild. On the other hand, if
+          lstat() is unresolved at link time, add -DNOLSTAT to CFLAGS. If
+          readlink() is also unresolved, add -DNOSYMLINK.
+
+   realpath()
+          Link-time complains about realpath() -- find the library in
+          which it resides and add it to LIBS (example for Unixware 7.1:
+          "-lcudk70") or add -DNOREALPATH to CFLAGS and rebuild. If built
+          with realpath() but debug log file is truncated or mangled,
+          ditto (some realpath() implementations behave differently from
+          others). If built with realpath() and seemingly random core
+          dumps occur during file path resolution, ditto.
+
+   Failure to locate header file <term.h>
+          Usually happens on Linux systems that have the C compiler
+          installed, but not the ncurses package (see comments about
+          selective installs above). Go back and install ncurses, or use
+          "make linuxnc" (Linux No Curses).
+
+   "Can't find shared library libc.so.2.1"
+   "Can't find shared library libncurses.so.3.0", etc...
+          You are trying to run a binary that was built on a computer
+          that has different library versions than your computer, and
+          your computer's loader is picky about library version numbers.
+          Rebuild from source on your computer.
+
+   Time (struct tm) related difficulties:
+          Errors like the following:
+
+"ckutio.c", line 11994: incomplete struct/union/enum tm: _tm
+"ckutio.c", line 11995: error: cannot dereference non-pointer type
+"ckutio.c", line 11995: error: assignment type mismatch
+"ckutio.c", line 11997: warning: using out of scope declaration: localtime
+"ckutio.c", line 11997: error: unknown operand size: op "="
+"ckutio.c", line 11997: error: assignment type mismatch
+"ckutio.c", line 11998: error: undefined struct/union member: tm_year
+"ckutio.c", line 12000: error: undefined struct/union member: tm_mon
+"ckutio.c", line 12001: error: undefined struct/union member: tm_mday
+"ckutio.c", line 12002: error: undefined struct/union member: tm_hour
+"ckutio.c", line 12003: error: undefined struct/union member: tm_min
+"ckutio.c", line 12004: error: undefined struct/union member: tm_sec
+
+          are due to failure to include the appropriate time.h header
+          files. Unix platforms generally have one or more of the
+          following: <time.h>, <sys/time.h>, and <sys/timeb.h>. Any
+          combination of these might be required. Defaults are set up for
+          each makefile target. The defaults can be corrected on the CC
+          command line by adding the appropriate definition from the
+          following list to CFLAGS:
+
+-DTIMEH         Include <time.h>
+-DNOTIMEH       Don't include <time.h>
+-DSYSTIMEH      Include <sys/time.h>
+-DNOSYSTIMEH    Don't include <sys/time.h>
+-DSYSTIMEBH     Include <sys/timeb.h>
+-DNOSYSTIMEBH   Don't include <sys/timeb.h>
+
+          Note that <sys/timeb.h> is relatively scarce in the System V
+          and POSIX environments; the only platform of recent vintage
+          where it was/is used is OSF/1 and its derivatives (Digital Unix
+          and Tru64 Unix).
+
+   Struct timeval and/or timezone not declared:
+          In some cases, merely including the appropriate time.h header
+          files is still not enough. POSIX.1 does not define the timeval
+          struct, and so the items we need from the header are protected
+          against us by #ifndef _POSIX_SOURCE or somesuch. In this case,
+          we have to declare the timeval (and timezone) structs
+          ourselves. To force this, include -DDCLTIMEVAL in CFLAGS.
+
+   Warnings about dn_expand() Argument #4
+          WARNING: argument is incompatible with prototyp. It's the old
+          char versus unsigned char stupidity again. Try to find a
+          compiler switch like GCC's "-funsigned-char". Failing that, add
+          -DCKQUERYTYPE=xxx to CFLAGS, where xxx is whatever 'man
+          dn_expand' tells you the type of the 4th argument should be
+          (presumably either char or unsigned char; in the latter case
+          use CHAR to avoid confusion caused by multiple words.
+
+   Switch Table Overflow (in [112]ckcuni.c)
+          Add -DNOUNICODE to CFLAGS.
+
+   Compile-time warnings about ck_out() or tgetstr() or tputs():
+          Easy solution: Add -DNOTERMCAP to CFLAGS. But then you lose the
+          SCREEN function. Real solution: Try all different combinations
+          of the following CFLAGS:
+
+-DTPUTSARGTYPE=char    -DTPUTSFNTYPE=int
+-DTPUTSARGTYPE=int     -DTPUTSFNTYPE=void
+
+          Until the warnings go away, except maybe "ck_outc: return with
+          a value in a function returning void", and in that case also
+          add -DTPUTSISVOID.
+
+   "Passing arg 1 of to tputs() makes pointer from integer without a
+          cast":
+          Add -DTPUTSARG1CONST to CFLAGS.
+
+   "Undefined symbol: dup2"
+          Add -DNOZEXEC to CFLAGS.
+
+   "header file 'termcap.h' not found"
+          Add -DNOHTERMCAP to CFLAGS.
+
+   Other difficulties are generally of the "where is curses.h and what is
+   it called this week?" variety (most easily solved by making symlinks
+   in the include and lib directories), or overzealous complaints
+   regarding type mismatches in function calls because of the totally
+   needless and silly signed versus unsigned char conflict (*), etc. In
+   any case, please send any compilation or linking warnings or errors to
+   the author, preferably along with fixes.
+
+     * C-Kermit does not use the signed property of chars at all
+       anywhere, ever. So if all chars and char *'s can be made unsigned
+       at compile time, as they can in gcc with "-funsigned-char", they
+       should be.
+
+   IMPORTANT: If you find any of these hints necessary for a particular
+   make target (or you hit upon others not listed here), PLEASE SEND A
+   REPORT TO:
+
+[113]kermit-support@columbia.edu
+    ________________________________________________________________________
+
+  4.1. The Unix Makefile
+
+   [ [114]Top ] [ [115]Contents ] [ [116]Section Contents ] [ [117]Next ]
+   [ [118]Previous ]
+
+   If your distribution does not contain a file with the name "makefile"
+   or "Makefile", then rename the file called ckuker.mak to makefile:
+
+mv ckuker.mak makefile
+
+   Then type "make xxx", where xxx is the platform you want to build
+   C-Kermit for. These are listed in the [119]comments at the top of the
+   makefile. For example, to build C-Kermit for Linux, type:
+
+make linux
+
+   Here are some typical examples:
+
+     Target    Description
+     linux     Linux, any version on any hardware platform
+     openbsd   OpenBSD, any version on any hardware platform
+     aix43     AIX 4.3
+     aix43g    AIX 4.3, built with gcc
+     solaris9  Solaris 9
+     solaris9g Solaris 9 built with gcc
+     hpux1100  HP-UX 11-point-anything
+
+   The makefile is quite long, and at least two versions of Unix, SCO
+   Xenix/286 and 2.x BSD, cannot cope with its length. An attempt to
+   "make sco286" gives the message "Make: Cannot alloc mem for env..
+   Stop". Solution: edit away some or all of the nonrelevant material
+   from the makefile. (A separate version of the makefile is provided for
+   BSD 2.x: ckubs2.mak but C-Kermit 8.0 can't be built for BSD 2.x -- it
+   has simply grown too large.)
+
+   Some make programs reportedly cannot handle continued lines (lines
+   ending in backslash (\)). If you have a problem with the makefile, try
+   editing the makefile to join the continued lines (remove the
+   backslashes and the following linefeed).
+
+   Other makefile troubles may occur because tabs in the makefile have
+   somehow been converted to spaces. Spaces and tabs are distinct in Unix
+   makefiles.
+
+   Similarly, carriage returns might have been added to the end of each
+   line, which also proves confusing to most Unix versions of make.
+
+   Check to see if there are comments about your particular version in
+   its makefile target itself. In a text editor such as EMACS or VI,
+   search for the make entry name followed by a colon, e.g. "linux:" (if
+   you really are building C-Kermit for Linux, do this now).
+
+   Check to see if there are comments about your particular version in
+   the [120]ckubwr.txt file ([121]CLICK HERE for the Web version).
+
+   If you have trouble with building [122]ckwart.c, or running the
+   resulting wart preprocessor program on [123]ckcpro.w:
+
+    1. Just "touch" the [124]ckcpro.c file that comes in the distribution
+       and then give the "make" command again, or:
+    2. Compile ckwart.c "by hand": cc -o wart ckwart.c, or:
+    3. Try various other tricks. E.g. one Linux user reported that that
+       adding the "static" switch to the rule for building wart fixed
+       everything:
+
+wart: ckwart.$(EXT)
+        $(CC) -static -o wart ckwart.$(EXT) $(LIBS)
+
+   If your compiler supports a compile-time option to treat ALL chars
+   (and char *'s, etc) as unsigned, by all means use it -- and send me
+   email to let me know what it is (I already know about gcc
+   -funsigned-char).
+
+   To add compilation options (which are explained later in this
+   document) to your makefile target without editing the makefile,
+   include "KFLAGS=..." on the make command line, for example:
+
+make linux KFLAGS=-DNODEBUG
+make bsd "KFLAGS=-DKANJI -DNODEBUG -DNOTLOG -DDYNAMIC -UTCPSOCKET"
+
+   Multiple options must be separated by spaces. Quotes are necessary if
+   the KFLAGS= clause includes spaces. The KFLAGS are added to the end of
+   the CFLAGS that are defined in the selected makefile target. For
+   example, the "bsd" entry includes -DBSD4 -DTCPSOCKET, so the second
+   example above compiles Kermit with the following options:
+
+-DBSD4 -DTCPSOCKET -DKANJI -DNODEBUG -DNOTLOG -DDYNAMIC -UTCPSOCKET
+
+   (Notice how "-UTCPSOCKET" is used to negate the effect of the
+   "-DTCPSOCKET" option that is included in the makefile target.)
+
+   WARNING: Be careful with KFLAGS. If you build C-Kermit, change some
+   files, and then run make again using the same make entry but
+   specifying different KFLAGS than last time, make won't detect it and
+   you could easily wind up with inconsistent object modules, e.g. some
+   of them built with a certain option, others not. When in doubt, "make
+   clean" first to make sure all your object files are consistent.
+   Similarly, if you change CFLAGS, LIBS, or any other items in the
+   makefile, or you rebuild using a different makefile target, "make
+   clean" first.
+
+   If you create a new makefile target, use static linking if possible.
+   Even though this makes your C-Kermit binary bigger, the resulting
+   binary will be more portable. Dynamically linked binaries tend to run
+   only on the exact configuration and version where they were built; on
+   others, invocation tends to fail with a message like:
+
+Can't find shared library "libc.so.2.1"
+    ________________________________________________________________________
+
+  4.2. The C-Kermit Initialization File
+
+   [ [125]Top ] [ [126]Contents ] [ [127]Section Contents ] [ [128]Next ]
+   [ [129]Previous ]
+
+   (This section is obsolete.) Read [130]Section 5 about the
+   initialization file.
+    ________________________________________________________________________
+
+  4.3. The 2.x BSD Makefile
+
+   [ [131]Top ] [ [132]Contents ] [ [133]Section Contents ] [ [134]Next ]
+   [ [135]Previous ]
+
+     This section is obsolete. C-Kermit 6.0 was the last release that
+     could be built on PDP-11 based BSD versions.
+    ________________________________________________________________________
+
+  4.4. The Plan 9 Makefile
+
+   [ [136]Top ] [ [137]Contents ] [ [138]Section Contents ] [ [139]Next ]
+   [ [140]Previous ]
+
+   Use the separate makefile [141]ckpker.mk. NOTE: The Plan 9 version of
+   C-Kermit 8.0 has not yet been built. There should be no impediment to
+   building it. However, even when built successfully, certain key
+   features are missing, notably TCP/IP networking.
+    ________________________________________________________________________
+
+  4.5. Makefile Failures
+
+   [ [142]Top ] [ [143]Contents ] [ [144]Section Contents ] [
+   [145]Previous ]
+
+   First, be sure the source files are stored on your current disk and
+   directory with the right names (in lowercase). Second, make sure that
+   the makefile itself does not contain any lines with leading spaces:
+   indented lines must all start with horizontal TAB, and no spaces.
+
+   Then make sure that your Unix PATH is defined to find the appropriate
+   compiler for your makefile target. For example, on SunOS systems,
+   "make sunos41" builds C-Kermit for the BSD environment, and assumes
+   that /usr/ucb/cc will be used for compilation and linking. If your
+   PATH has /usr/5bin ahead of /usr/ucb, you can have problems at compile
+   or link time (a commonly reported symptom is the inability to find
+   "ftime" during linking). Fix such problems by redefining your Unix
+   PATH, or by specifying the appropriate "cc" in CC= and CC2= statements
+   in your makefile target.
+
+   During edits 166-167, considerable effort went into making C-Kermit
+   compilable by ANSI C compilers. This includes prototyping all of
+   C-Kermit's functions, and including the ANSI-defined system header
+   files for system and library functions, as defined in K&R, second
+   edition: <string.h>, <stdlib.h>, <unistd.h> (except in NeXTSTEP this
+   is <libc.h>), and <sys/stdtypes.h>. If you get warnings about any of
+   these header files not being found, or about argument mismatches
+   involving pid_t, uid_t, or gid_t, look in ckcdeb.h and make
+   amendments. C-Kermit assumes it is being compiled by an ANSI-compliant
+   C compiler if __STDC__ is defined, normally defined by the compiler
+   itself. You can force ANSI compilation without defining __STDC__
+   (which some compilers won't let you define) by including -DCK_ANSIC on
+   the cc command line.
+
+   On the other hand, if your compiler defines __STDC__ but still
+   complains about the syntax of Kermit's function prototypes, you can
+   disable the ANSI-style function prototyping by including -DNOANSI on
+   the command line.
+
+   For SCO OpenServer, UNIX, ODT, and XENIX compilations, be sure to pick
+   the most appropriate [146]makefile target, and be sure you have
+   installed an SCO development system that is keyed to your exact SCO
+   operating system release, down to the minor version (like 2.3.1).
+
+   Also note that SCO distributes some of its libraries in encrypted
+   form, and they must be decrypted before C-Kermit can be linked with
+   them. If not, you might see a message like:
+
+ld: file /usr/lib/libsocket.a is of unknown type: magic number = 6365
+
+   To decrypt, you must supply a key (password) that came with your
+   license. Call SCO for further info.
+
+   If your compiler uses something other than int for the pid (process
+   id) data type, put -DPID_T=pid_t or whatever in your CFLAGS.
+
+   If you get complaints about unknown data types uid_t and gid_t, put
+   -DUID_T=xxx -DGID_T=yyy in your CFLAGS, where xxx and yyy are the
+   appropriate types.
+
+   If your compilation fails because of conflicting or duplicate
+   declarations for sys_errlist, add -DUSE_STRERROR or -DNDSYSERRLIST to
+   CFLAGS.
+
+   If your compilation dies because getpwnam() is being redeclared (or
+   because of "conflicting types for getwpnam"), add -DNDGPWNAM to your
+   CFLAGS. If that doesn't work, then add -DDCGPWNAM to your CFLAGS (see
+   ckufio.c around line 440).
+
+   If the compiler complains about the declaration of getpwnam() during
+   an ANSI C compilation, remove the declaration from ckufio.c or change
+   the argument in the prototype from (char *) to (const char *).
+
+   If you get complaints that getpwuid() is being called with an improper
+   type, put -DPWID_T=xx in your CFLAGS.
+
+   If you get compile-time warnings that t_brkc or t_eofc (tchars
+   structure members, used in BSD-based versions) are undefined, or
+   structure-member- related warnings that might be traced to this fact,
+   add -DNOBRKC to CFLAGS.
+
+   If you get a linker message to the effect that _setreuid or _setregid
+   is not defined, add -DNOSETREU to CFLAGS, or add -DCKTYP_H=blah to
+   CFLAGS to make C-Kermit read the right <types.h>-kind-of-file to pick
+   up these definitions.
+
+   If you get a message that _popen is undefined, add -DNOPOPEN to
+   CFLAGS.
+
+   If you get a complaint at compile time about an illegal
+   pointer-integer combination in ckufio.c involving popen(), or at link
+   time that _popen is an undefined symbol, add the declaration "FILE
+   *popen();" to the function zxcmd() in ckufio.c (this declaration is
+   supposed to be in <stdio.h>). If making this change does not help,
+   then apparently your Unix does not have the popen() function, so you
+   should add -DNOPOPEN to your make entry, in which case certain
+   functions involving "file" i/o to the standard input and output of
+   subprocesses will not be available.
+
+   If your linker complains that _getcwd is undefined, you can add a
+   getcwd() function to ckufio.c, or add it to your libc.a library using
+   ar:
+
+#include <stdio.h>
+
+char *
+getcwd(buf,size) char *buf; int size; {
+#ifndef NOPOPEN
+#ifdef DCLPOPEN
+    FILE *popen();
+#endif
+    FILE *pfp;
+
+    if (!buf) return(NULL);
+    if (!(pfp = popen("pwd","r"))) return(NULL);
+    fgets(buf,size-2,pfp);
+    pclose(pfp);
+    buf[strlen(buf)-1] = '\0';
+    return((char *)buf);
+#else
+    buf[0] = '\0';
+    return(NULL);
+#endif /* NOPOPEN */
+}
+
+#ifdef NOPOPEN
+FILE *popen(s,t) char *s,*t; {
+    return(NULL);
+}
+#endif /* NOPOPEN */
+
+   If you get complaints about NPROC having an invalid value, add a valid
+   definition for it (depends on your system), as in the cray entry.
+
+   If you get some symbol that's multiply defined, it probably means that
+   a variable name used by Kermit is also used in one of your system
+   libraries that Kermit is linked with. For example, under PC/IX some
+   library has a variable or function called "data", and the variable
+   "data" is also used extensively by Kermit. Rather than edit the Kermit
+   source files, just put a -D in the make entry CFLAGS to change the
+   Kermit symbol at compile time. In this example, it might be
+   -Ddata=xdata.
+
+   Some symbol is defined in your system's header files, but it produces
+   conflicts with, or undesired results from, Kermit. Try undefining the
+   symbol in the makefile target's CFLAGS, for example -UFIONREAD.
+
+   Some well-known symbol is missing from your system header files. Try
+   defining in the makefile target's CFLAGS, for example -DFREAD=1.
+
+   You get many warnings about pointer mismatches. This probably means
+   that Kermit is assuming an int type for signal() when it should be
+   void, or vice-versa. Try adding -DSIG_I (for integer signal()) or
+   -DSIG_V (for void) to CFLAGS. Or just include KFLAGS=-DSIG_V (or
+   whatever) in your "make" command, for example:
+
+make bsd KFLAGS=-DSIG_V
+
+   You get many messages about variables that are declared and/or set but
+   never used. It is difficult to avoid these because of all the
+   conditional compilation in the program. Ignore these messages.
+
+   Some of C-Kermit's modules are so large, or contain so many character
+   string constants, or are so offensive in some other way, that some C
+   compilers give up and refuse to compile them. This is usually because
+   the -O (optimize) option is included in the make entry. If this
+   happens to you, you can (a) remove the -O option from the make entry,
+   which will turn off the optimizer for ALL modules; or (b) compile the
+   offending module(s) by hand, including all the switches from make
+   entry except for -O, and then give the appropriate "make" command
+   again; or (c) increase the value of the -Olimit option, if your
+   compiler supports this option; or (d) change the [147]makefile target
+   to first compile each offending module explicitly without
+   optimization, then compile the others normally (with optimization),
+   for example:
+
+#Fortune 32:16, For:Pro 2.1 (mostly like 4.1bsd)
+ft21:
+        @echo 'Making C-Kermit $(CKVER) for Fortune 32:16 For:Pro 2.1...'
+        $(MAKE) ckuusx.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \
+        -SYM 800 \ -DDYNAMIC -DNOSETBUF -DCK_CURSES $(KFLAGS) -DPID_T=short"
+        $(MAKE) ckuxla.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \
+        -SYM 800 \ -DDYNAMIC -DNOSETBUF -DCK_CURSES $(KFLAGS) -DPID_T=short"
+        $(MAKE) ckudia.$(EXT) "CFLAGS= -DNODEBUG -DBSD4 -DFT21 -DNOFILEH \
+        -SYM 800 \ -DDYNAMIC -DNOSETBUF -DCK_CURSES $(KFLAGS) -DPID_T=short"
+        $(MAKE) wermit "CFLAGS= -O -DNODEBUG -DBSD4 -DFT21 -DNOFILEH -SYM 800 \
+        -DDYNAMIC -DNOSETBUF -DCK_CURSES $(KFLAGS) -DPID_T=short" \
+        "LNKFLAGS= -n -s" "LIBS= -lcurses -ltermcap -lv -lnet"
+
+   As an extreme example, some compilers (e.g. gcc on the DG AViiON) have
+   been known to dump core when trying to compile ckwart.c with
+   optimization. So just do this one "by hand":
+
+cc -o wart ckwart.c
+
+   or:
+
+touch ckcpro.c
+
+   and then give the "make" command again.
+
+   Speaking of wart, it is unavoidable that some picky compilers might
+   generate "statement unreachable" messages when compiling ckcpro.c.
+   Unreachable statements can be generated by the wart program, which
+   generates ckcpro.c automatically from [148]ckcpro.w, which translates
+   lex-like state/input constructions into a big switch/case
+   construction.
+
+   Some function in Kermit wreaks havoc when it is called. Change all
+   invocations of the function into a macro that evaluates to the
+   appropriate return code that would have been returned by the function
+   had it been called and failed, for example: -Dzkself()=0. Obviously
+   not a good idea if the function is really needed.
+
+   If you have just installed SunOS 4.1.2 or 4.1.3, you might find that
+   C-Kermit (and any other C program) fails to link because of unresolved
+   references from within libc. This is because of a mistake in Sun's
+   /usr/lib/shlib.etc files for building the new libc. Change the libc
+   Makefile so that the "ld" lines have "-ldl" at the end. Change the
+   README file to say "mv xccs.multibyte. xccs.multibyte.o" and follow
+   that instruction.
+  __________________________________________________________________________
+
+5. INSTALLING THE KERMIT FILES
+
+   [ [149]Top ] [ [150]Contents ] [ [151]Next ] [ [152]Previous ]
+
+   SECTION CONTENTS
+
+5.1. [153]The C-Kermit Initialization File
+5.2. [154]Text Files
+5.3. [155]Installing the Kermit Files
+5.4. [156]The Makefile Install Target
+
+   The C-Kermit executable does not need any external files to run.
+   Unlike, say, the cu program, which on most platforms is useless unless
+   you (as root) edit the /usr/spool/uucp/Systems and
+   /usr/spool/uucp/Devices files to supply whatever obscure and
+   undocumented syntax is required to match some supposedly user-friendly
+   mnemonic to the real pathname of whatever device you want to use,
+   Kermit runs on its own without needing any external configuration
+   files, and lets you refer to device (and network hosts and services)
+   by their own natural undisguised names.
+
+   Nevertheless, a number of external files can be installed along with
+   the C-Kermit executable if you wish. These include configuration and
+   customization files that are read by Kermit as well as documentation
+   files to be read by people. All of this material is (a) optional, and
+   (b) available on the Kermit website:
+
+[157]http://www.columbia.edu/kermit/
+
+   and usually in a more pleasant form, perhaps also with updated
+   content. So if your computer is on the Internet, there is no need to
+   install anything but the Kermit executable if users know how to find
+   the Kermit website (and if they don't, Kermit's "help" command tells
+   them).
+
+  5.1. The C-Kermit Initialization File
+
+   In C-Kermit 7.0 and earlier, the standard initialization file was a
+   key C-Kermit component because:
+
+    a. It "loaded" the dialing and network directories.
+    b. It defined all the macros and variables for the services
+       directory.
+    c. It defined macros for quickly changing Kermit's file-transfer
+       performance tuning.
+
+   The standard initialization file is quite long (more than 600 lines)
+   and requires noticeable processing time (the slower the computer, the
+   more noticeable), yet few people actually use the services directory,
+   whose definition takes up most of its bulk. Meanwhile, in C-Kermit
+   8.0, many of the remaining functions of the standard initialization
+   file are now built in; for example, the FAST, CAUTIOUS, and ROBUST
+   commands.
+
+   More to the point, many of the settings that could be made only in the
+   initialization and customization files can now be picked up from
+   environment variables. The first group identifies initialization and
+   directory files:
+
+   CKERMIT_INI
+          The path of your Kermit initialization file, if any. This
+          overrides the built-in search for $HOME/.kermrc.
+
+   K_CHARSET
+          The character set used for encoding local text files.
+          Equivalent to SET FILE CHARACTER-SET.
+
+   K_DIAL_DIRECTORY
+          The full pathname of one or more Kermit dialing directory
+          files. Equivalent to SET DIAL DIRECTORY.
+
+   K_NET_DIRECTORY
+          The full pathname of one or more Kermit network directory
+          files. Equivalent to SET NETWORK DIRECTORY.
+
+   K_INFO_DIRECTORY
+   K_INFO_DIR
+          The full pathname of a directory containing Kermit (if any)
+          containing ckubwr.txt and other Kermit text files. Overrides
+          Kermit's built-in search for this directory.
+
+   The next group is related to dialing modems:
+
+   K_COUNTRYCODE
+          The telephonic numeric country code for this location, e.g. 1
+          for North America or 39 for Italy. It is recommended that this
+          one be set for all users, system-wide. Not only is it used to
+          process portable-format dialing directory entries, but it is
+          also compared against Kermit's built-in list of "tone
+          countries" to see if tone dialing can be used. Equivalent to
+          Kermit's SET DIAL COUNTRY-CODE command.
+
+   K_AREACODE
+          The telephonic numeric area code for this location, e.g. 212
+          for Manhattan, New York, USA. Recommend this one also be set
+          system-wide, so shared portable-format dialing directories will
+          work automatically for everybody. Equivalent to Kermit's SET
+          DIAL AREA-CODE command.
+
+   K_DIAL_METHOD
+          TONE or PULSE. Equivalent to Kermit's SET DIAL METHOD command.
+          If a dial method is not set explicitly (or implicitly from the
+          country code), Kermit does not specify a dialing method, and
+          uses the modem's default method, which tends to be pulse.
+
+   K_INTL_PREFIX
+          The telephonic numeric international dialing prefix for this
+          location. Equivalent to Kermit's SET DIAL INTL-PREFIX command.
+
+   K_LD_PREFIX
+          The telephonic numeric long-distance dialing prefix for this
+          location. Equivalent to Kermit's SET DIAL LD-PREFIX command.
+
+   K_PBX_ICP
+          The telephonic numeric PBX internal call prefix for this
+          location. Equivalent to Kermit's SET DIAL PBX-INSIDE-PREFIX
+          command.
+
+   K_PBX_OCP
+          The telephonic numeric PBX external call prefix for this
+          location. Equivalent to Kermit's SET DIAL PBX-OUTSIDE-PREFIX
+          command.
+
+   K_PBX_XCH
+          The telephonic numeric PBX exchange (first part of the
+          subscriber number). Equivalent to Kermit's SET DIAL
+          PBX-EXCHANGE command.
+
+   K_TF_AREACODE
+          A list of one or more telephonic numeric toll-free area codes.
+
+   K_TF_PREFIX
+          The telephonic numeric toll-free dialing prefix, in case it is
+          different from the long-distance prefix. Equivalent to Kermit's
+          SET DIAL TF-PREFIX command.
+
+   The final group includes well-known environment variables that are
+   also used by Kermit:
+
+   CDPATH
+          Where the CD command should look for relative directory names.
+
+   SHELL
+          The path of your Unix shell. Used by the RUN (!) command to
+          choose the shell to execute its arguments.
+
+   USER
+          Your Unix username.
+
+   EDITOR
+          The name or path of your preferred editor (used by the EDIT
+          command). Equivalent to SET EDITOR.
+
+   BROWSER
+          The name or path of your preferred web browser (used by the
+          BROWSE command). Equivalent to Kermit's SET BROWSER command.
+
+   Does this mean the initialization file can be abolished? I think so.
+   Here's why:
+
+     * Kermit already does everything most people want it to do without
+       one.
+     * Important site-specific customizations can be done with global
+       environment variables.
+     * There is no longer any need for everybody to have to use the
+       standard initialization file.
+     * This means that your initialization file, if you want one, can
+       contain your own personal settings, definitions, and preferences,
+       rather than 600 lines of "standard" setups.
+     * If you still want the services directory, you can either TAKE the
+       standard initialization file (which must be named anything other
+       than $HOME/.kermrc to avoid being executed automatically every
+       time you start Kermit), or you can make it a kerbang script and
+       execute it "directly" (the [158]makefile install target does this
+       for you by putting ckermit.ini in the same directory as the Kermit
+       binary, adding the appropriate Kerbang line to the top, and giving
+       it execute permission).
+
+   In fact, you can put any number of kerbang scripts in your PATH to
+   start up C-Kermit in different ways, to have it adopt certain
+   settings, make particular connections, execute complicated scripts,
+   whatever you want.
+
+  5.2. Text Files
+
+   These are entirely optional. Many of them are to be found at the
+   Kermit website in HTML form (i.e. as Web pages with clickable links,
+   etc), and very likely also more up to date. Plain-text files that
+   correspond to Web pages were simply "dumped" by Lynx from the website
+   to plain ASCII text. The format is whatever Lynx uses for this
+   purpose. If you wish, you can install them on your computer as
+   described in the [159]next section.
+
+   [160]COPYING.TXT
+          Copyright notice, permissions, and disclaimer.
+
+   [161]ckermit.ini
+          The standard initialization file, intended more for reference
+          (in most cases) than actual use; see [162]Section 5.1.
+
+   [163]ckermod.ini
+          A sample customization file.
+
+   [164]ckermit70.txt
+          Supplement to [165]Using C-Kermit for version 7.0. Available on
+          the Kermit website as:
+          [166]http://www.columbia.edu/kermit/ckermit70.html
+
+   [167]ckermit80.txt
+          Supplement to [168]Using C-Kermit for version 8.0. Available on
+          the Kermit website as:
+          [169]http://www.columbia.edu/kermit/ckermit80.html
+
+   [170]ckcbwr.txt
+          The general C-Kermit hints and tips ("beware") file. Available
+          on the Kermit website as:
+          [171]http://www.columbia.edu/kermit/ckcbwr.html
+
+   [172]ckubwr.txt
+          The Unix-specific C-Kermit hints and tips file. Available on
+          the Kermit website as:
+          [173]http://www.columbia.edu/kermit/ckubwr.html
+
+   [174]ckuins.txt
+          Unix C-Kermit Installation Instructions (this file). Available
+          on the Kermit website as:
+          [175]http://www.columbia.edu/kermit/ckuins.html
+
+   [176]ckccfg.txt
+          C-Kermit compile-time configuration options. Available on the
+          Kermit website as:
+          [177]http://www.columbia.edu/kermit/ckccfg.html
+
+   [178]ckcplm.txt
+          The C-Kermit program logic manual. Available on the Kermit
+          website as:
+          [179]http://www.columbia.edu/kermit/ckcplm.html
+
+   [180]ca_certs.pem
+          Certificate Authority certificates for secure connections (see
+          [181]Section 16).
+
+  5.3. Installing the Kermit Files
+
+   There is an "install" target in the [182]makefile that you can use if
+   you wish. However, since every site has its own layout and
+   requirements, it is often better to install the Kermit files by hand.
+   You don't have to use the makefile install target to install C-Kermit.
+   This is especially true since not all sites build C-Kermit from
+   source, and therefore might not even have the makefile. But you should
+   read this section in any case.
+
+     If your computer already has an older version of C-Kermit
+     installed, you should rename it (e.g. to "kermit6" or "kermit7") so
+     in case you have any trouble with the new version, the old one is
+     still available.
+
+   In most cases, you need to be root to install C-Kermit, if only to
+   gain write access to directories in which the binary and manual page
+   are to be copied. The C-Kermit binary should be installed in a
+   directory that is in the users' PATH, but that is not likely to be
+   overwritten when you install a new version of the operating system. A
+   good candidate would be the /usr/local/bin/ directory, but the
+   specific choice is site dependent. Example (assuming the appropriate
+   Kermit binary is stored in your current directory as "wermit", e.g.
+   because you just built it from source and that's the name the makefile
+   gave it):
+
+mv wermit /usr/local/bin/kermit
+chmod 755 /usr/local/bin/kermit
+
+   or (only after you finish reading this section!) simply:
+
+make install
+
+   IMPORTANT: IF C-KERMIT IS TO BE USED FOR DIALING OUT, you must also do
+   something to give it access to the dialout devices and lockfile
+   directories. The 'install' target does not attempt to set Kermit's
+   owner, group, and permissions to allow dialing out. This requires
+   privileges, open eyes, and human decision-making. Please read
+   [183]Sections 10 and [184]11 below, make the necessary decisions, and
+   then implement them by hand as described in those sections.
+
+   You should also install the man page, which is called ckuker.nr, in
+   the man page directory for local commands, such as /usr/man/man1/,
+   renamed appropriately, e.g. to kermit.1. This is also taken care of by
+   "make install".
+
+   Optionally, the text files listed in the [185]previous section can be
+   placed in a publicly readable directory. Suggested directory names
+   are:
+
+/usr/local/doc/kermit/
+/usr/local/lib/kermit/
+/usr/share/lib/kermit/
+/opt/kermit/doc/
+
+   (or any of these without the "/kermit"). Upon startup, C-Kermit checks
+   the following environment variables whose purpose is to specify the
+   directory where the C-Kermit text files are, in the following order:
+
+K_INFO_DIRECTORY
+K_INFO_DIR
+
+   If either of these is defined, C-Kermit checks for the existence of
+   the ckubwr.txt file (Unix C-Kermit Hints and Tips). If not found, it
+   checks the directories listed above (both with and without the
+   "/kermit") plus several others to see if they contain the ckubwr.txt
+   file. If found, various C-Kermit messages can refer the user to this
+   directory.
+
+   Finally, if you want to put the source code files somewhere for people
+   to look at, you can do that too.
+
+  5.4. The Makefile Install Target
+
+   The makefile "install" target does almost everything for you if you
+   give it the information it needs by setting the variables described
+   below. You can use this target if:
+
+     * You downloaded the [186]complete C-Kermit archive and built
+       C-Kermit from source; or:
+     * You downloaded an [187]individual C-Kermit binary and the
+       [188]C-Kermit text-file archive, and your computer has a "make"
+       command.
+
+   Here are the parameters you need to know:
+
+   BINARY
+          Name of the binary you want to install as "kermit". Default:
+          "wermit".
+
+   prefix
+          (lower case) If you define this variable, its value is
+          prepended to all the following xxxDIR variables (8.0.211 and
+          later).
+
+   DESTDIR
+          If you want to install the Kermit files in a directory
+          structure like /opt/kermit/bin/, /opt/kermit/doc/,
+          /opt/kermit/src/, then define DESTIR as the root of this
+          structure; for example, /opt/kermit. The DESTDIR string should
+          not end with a slash. By default, DESTDIR is not defined. If it
+          is defined, but the directory does not exist, the makefile
+          attempts to create it, which might require you to be root. Even
+          so, this can fail if any segments in the path except the last
+          one do not already exist. WARNING: If the makefile creates any
+          directories, it gives them a mode of 755, and the default owner
+          and group. Modify these by hand if necessary.
+
+   BINDIR
+          Directory in which to install the Kermit binary (and the
+          standard C-Kermit initialization file, if it is found, as a
+          Kerbang script). If DESTDIR is defined, BINDIR must start with
+          a slash. BINDIR must not end with a slash. If DESTDIR is
+          defined, BINDIR is a subdirectory of DESTDIR. If BINDIR does
+          not exist, the makefile attempts to create it as with DESTDIR.
+          Default: /usr/local/bin.
+
+   MANDIR
+          Directory in which to install the C-Kermit manual page as
+          "kermit" followed by the manual-chapter extension (next item).
+          Default: /usr/man/man1. If MANDIR is defined, the directory
+          must already exist.
+
+   MANEXT
+          Extension for the manual page. Default: 1 (digit one).
+
+   SRCDIR
+          Directory in which to install the C-Kermit source code. If
+          DESTDIR is defined, this is a subdirectory of DESTDIR. Default:
+          None.
+
+   CERTDIR
+          For secure builds only: Directory in which to install the
+          ca_certs.pem file. This must be the verification directory used
+          by programs that use the SSL libraries at your site. Default:
+          none. Possibilities include: /usr/local/ssl, /opt/ssl,
+          /usr/lib/ssl, . . .     If CERTDIR is defined, the directory
+          must already exist.
+
+   INFODIR
+          Directory in which to install the C-Kermit text files. If
+          DESTDIR is defined, this is a subdirectory of DESTDIR. Default:
+          None. If INFODIR is defined but does not exist, the makefile
+          attempts to create it, as with DESTDIR.
+
+   Examples:
+
+   make install
+          Installs "wermit" as /usr/local/bin/kermit with permissions
+          755, the default owner and group, and no special privileges.
+          The manual page is installed as /usr/man/man1/kermit.1. Text
+          files are not copied anywhere, nor are the sources.
+
+   make MANDIR= install
+          Just like "make install" but does not attempt to install the
+          manual page.
+
+   make DESTDIR=/opt/kermit BINDIR=/bin SRCDIR=/src INFODIR=/doc install
+          Installs the Kermit binary "wermit" as /opt/kermit/bin/kermit,
+          puts the source code in /opt/kermit/src, and puts the text
+          files in /opt/kermit/doc, creating the directories if they
+          don't already exist, and puts the man page in the default
+          location.
+
+   make BINDIR=/usr/local/bin CERTDIR=/usr/local/ssl install
+          Installs the Kerberized Kermit binary "wermit" as
+          /usr/local/bin/kermit, puts the CA Certificates file in
+          /usr/local/ssl/, and the man page in the normal place.
+
+   For definitive information, see the makefile. The following is
+   excerpted from the 8.0.211 makefile:
+
+# The following symbols are used to specify library and header file locations
+# Redefine them to the values used on your system by:
+# . editing this file
+# . defining the values on the command line
+# . defining the values in the environment and use the -e option
+#
+prefix  = /usr/local
+srproot = $(prefix)
+sslroot = $(prefix)
+manroot = $(prefix)
+
+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
+...
+WERMIT = makewhat
+BINARY = wermit
+DESTDIR =
+BINDIR = $(prefix)/bin
+MANDIR = $(manroot)/man/man1
+MANEXT = 1
+SRCDIR =
+INFODIR =
+CERTDIR =
+  __________________________________________________________________________
+
+6. INSTALLING UNIX C-KERMIT FROM DOS-FORMAT DISKETTES
+
+   [ [189]Top ] [ [190]Contents ] [ [191]Next ] [ [192]Previous ]
+
+     This section is obsolete. We don't distribute C-Kermit on diskettes
+     any more because (a)there is no demand, and (b) it no longer fits. 
+
+   If you received a DOS-format diskette containing a binary executable
+   C-Kermit program plus supporting text files, be sure to chmod +x the
+   executable before attempting to run it.
+
+   In version 5A(190) and later, all the text files on the C-Kermit
+   DOS-format diskettes are in Unix format: LF at the end of each line
+   rather than CRLF. This means that no conversions are necessary when
+   copying to your Unix file system, and that all the files on the
+   diskette, text and binary, can be copied together. The following
+   comments apply to the DOS-format diskettes furnished with version
+   5A(189) and earlier or to other DOS-format diskettes you might have
+   obtained from other sources.
+
+   If you have received C-Kermit on MS-DOS format diskettes (such as
+   those distributed by Columbia University), you should make sure that
+   your DOS-to-Unix conversion utility (such as "dosread") both: (1)
+   changes line terminators in all files from carriage-return linefeed
+   (CRLF) to just linefeed (LF) (such as "dosread -a") and remove any
+   Ctrl-Z's, and (2) that all filenames are converted from uppercase to
+   lowercase. If these conversions were not done, you can use the
+   following shell script on your Unix system to do them:
+
+---(cut here)---
+#!/bin/sh
+#
+# Shell script to convert C-Kermit DOS-format files into Unix format.
+# Lowercases the filenames, strips out carriage returns and Ctrl-Z's.
+#
+x=$1 # the name of the source directory
+y=$2 # the name of the target directory if [ $# -lt 2 ]; then
+  echo "usage: $0 source-directory target-directory"
+  exit 1
+fi
+if cd $1 ; then
+  echo "Converting files from $1 to $2"
+else
+  echo "$0: cannot cd to $1"
+  exit 1
+fi
+for i in *; do
+  j=`echo $i | tr 'A-Z' 'a-z'`
+  echo $x/$i =\> $y/$j
+  tr -d '\015\032' < $i > $y/$j
+done
+---(cut here)---
+
+   Cut out this shell script, save it as "convert.sh" (or any other name
+   you prefer), then "chmod +x convert.sh". Then, create a new, empty
+   directory to put the converted files in, and then "convert.sh /xxx
+   /yyy" where /xxx is the name of the directory where the PC-format
+   files are, and /yyy is the name of the new, empty directory. The
+   converted files will appear in the new directory.
+  __________________________________________________________________________
+
+7. CHECKING THE RESULTS
+
+   [ [193]Top ] [ [194]Contents ] [ [195]Next ] [ [196]Previous ]
+
+   First some quick checks for problems that can be easily corrected by
+   recompiling with different options:
+
+   DIRECTORY listing is garbage
+          Permissions, size, and date are random garbage (but the
+          filenames are correct) in a C-Kermit DIRECTORY listing. On some
+          platforms, the lstat() function is present but simply doesn't
+          work; try adding -DNOLSTAT to CFLAGS and rebuild. If that
+          doesn't fix it, also add -DNOLINKBITS. If it's still not fixed,
+          remove -DNOLSTAT and -DNOLINKBITS and add -DNOSYMLINK.
+
+   curses
+          When you make a connection with C-Kermit and transfer files
+          using the fullscreen (curses) file-transfer display, and then
+          get the C-Kermit> prompt back afterwards, do characters echo
+          when you type them? If not, the curses library has altered the
+          buffering of /dev/tty. Try rebuilding with KFLAGS=-DCK_NEWTERM.
+          If it already has -DCK_NEWTERM in CFLAGS, try removing it. If
+          that doesn't help, then rebuild with -DNONOSETBUF (yes, two
+          NO's). If none of this works (and you can't fix the code), then
+          either don't use the fullscreen display, or rebuild with
+          -DNOCURSES.
+
+   Ctrl-L or any SCREEN command crashes C-Kermit:
+          Rebuild with -DNOTERMCAP.
+
+   No prompt after CONNECT:
+          After escaping back from CONNECT mode, does your C-Kermit>
+          prompt disappear? (Yet, typing "?" still produces a command
+          list, etc) In that case, add -DCKCONINTB4CB to CFLAGS and
+          rebuild.
+
+   Here is a more thorough checklist can use to tell whether your version
+   of C-Kermit was built correctly for your Unix system, with hints on
+   how to fix or work around problems:
+
+    a. Start C-Kermit (usually by typing "./wermit" in the directory
+       where you ran the makefile). Do you see the C-Kermit> prompt? If
+       not, C-Kermit incorrectly deduced that it was running in the
+       background. The test is in conbgt() in [197]ckutio.c. If you can
+       fix it for your system, please send in the fix (Hint: read about
+       "PID_T" below). Otherwise, you can force C-Kermit to foreground
+       mode by starting it with the -z command line option, as in "kermit
+       -z", or giving the interactive command SET BACKGROUND OFF.
+    b. When you type characters at the C-Kermit prompt, do they echo
+       immediately? If not, something is wrong with concb() and probably
+       the other terminal mode settings routines in [198]ckutio.c. Be
+       sure you have used the most appropriate make entry.
+    c. At the C-Kermit> prompt, type "send ./?". C-Kermit should list all
+       the files in the current directory. If not, it was built for the
+       wrong type of Unix file system. Details below. In the meantime,
+       try SET WILDCARD-EXPANSION SHELL as a workaround.
+    d. CD to a directory that contains a variety of files, symlinks, and
+       subdirectories and give a DIRECTORY command at the C-Kermit>
+       prompt. Do the permissions, size, and date appear correct? If not
+       see [199]Section 4.0.
+    e. Assuming your platform supports long file names, create a file
+       with a long name in your current directory, e.g.:
+
+$ touch thisisafilewithaveryveryveryveryveryveryveryverylooooooooongname
+
+       (you might need to make it longer than this, perhaps as long as
+       257 or even 1025 characters).
+       Check with ls to see if your version of Unix truncated the name.
+       Now start C-Kermit and type "send thisis<ESC>". Does Kermit
+       complete the name, showing the same name as ls did? If not, wrong
+       filesystem. Read on.
+    f. Make sure that Kermit has the maximum path length right. Just type
+       SHOW FILE and see what it says about this. If it is too short,
+       there could be some problems at runtime. To correct, look in
+       [200]ckcdeb.h to see how the symbol CKMAXPATH is set and make any
+       needed adjustments.
+    g. Send a file to your new Kermit program from a different Kermit
+       program that is known to work. Is the date/timestamp of the new
+       file identical to the original? If not, adjustments are needed in
+       zstrdt() in [201]ckufio.c.
+    h. Go to another computer (Computer B) from which you can send files
+       to C-Kermit. Connect Computer B to the computer (A) where you are
+       testing C-Kermit. Then:
+    i. Send a file from B to A. Make sure it transferred OK and was
+       created with the the right name.
+    j. Send a file from B to A, specifying an "as-name" that is very,
+       very long (longer than the maximum name length on computer A).
+       Check to make sure that the file was received OK and that its name
+       was truncated to Computer A's maximum length. If not, check the
+       MAXNAMLEN definition in [202]ckufio.c.
+    k. Tell C-Kermit on Computer A to "set receive pathnames relative"
+       and then send it a file from Computer B specifying an as-name that
+       contains several directory segments:
+
+send foo dir1/dir2/dir3/foo
+
+       Check to make sure that dir1/dir2/dir3/foo was created in Computer
+       A's current directory (i.e. that three levels of directories were
+       created).
+    l. Repeat step k, but make each path segment in the pathname longer
+       than Computer A's maximum name length. Make sure each directory
+       name, and the final filename, were truncated properly.
+    m. Type Ctrl-C (or whatever your Unix interrupt character is) at the
+       prompt. Do you get "^C..." and a new prompt? If instead, you get a
+       core dump (this shouldn't happen any more) "rm core" and then
+       rebuild with -DNOCCTRAP added to your CFLAGS. If it did work, then
+       type another Ctrl-C. If this does the same thing as the first one,
+       then Ctrl-C handling is OK. Otherwise, the SIGINT signal is either
+       not getting re-armed (shouldn't happen) or is being masked off
+       after the first time it is caught, in which case, if your Unix is
+       POSIX-based, try rebuilding C-Kermit with -DCK_POSIX_SIG.
+    n. Type Ctrl-Z (or whatever your Unix suspend character is) to put
+       C-Kermit in the background. Did it work? If nothing happened, then
+       (a)your version of Unix does not support job control, or (b) your
+       version of C-Kermit was probably built with -DNOJC. If your
+       session became totally frozen, then you are probably running
+       C-Kermit on a Unix version that supports job control, but under a
+       shell that doesn't. If that's not the case, look in the congm()
+       and psuspend() routines in [203]ckutio.c and see if you can figure
+       out what's wrong. If you can't, rebuild with -DNOJC.
+    o. Give a SET LINE command for a dialout device, e.g. "set line
+       /dev/tty00". If you got some kind of permission or access denied
+       message, go read [204]Section 10 and then come back here.
+    p. After giving a successful SET LINE command, type "show comm" to
+       see the communication parameters. Do they make sense?
+    q. Type "set speed ?" and observe the list of available speeds. Is it
+       what you expected? If not, see [205]Section 2) of the
+       [206]Configurations Options document.
+    r. Give a SET SPEED command to change the device's speed. Did it
+       work? (Type "show comm" again to check.)
+    s. Try dialing out: SET MODEM TYPE , SET LINE , SET SPEED , DIAL . If
+       it doesn't work, keep reading. After dialing, can you REDIAL?
+    t. If your version was built with TCP/IP network support, try the
+       TELNET command.
+    u. Transfer some files in remote mode on incoming asynchronous serial
+       (direct or modem) connections, and on incoming network (telnet,
+       rlogin, terminal server) connections. If you get lots of errors,
+       try different SET FLOW settings on the remote Kermit program.
+    v. Establish a serial connection from C-Kermit to another computer
+       (direct or dialed) and transfer some files. If you have network
+       support, do the same with a network connection.
+    w. If your version was built with fullscreen file transfer display
+       support, check that it works during local-mode file transfer.
+       Also, check C-Kermit's operation afterwards: is the echoing funny?
+       etc etc. If there are problems, see [207]Section 4.
+    x. If your version was built with script programming language
+       support, TAKE the ckedemo.ksc file to give it a workout.
+    y. Does C-Kermit interlock correctly with UUCP-family programs (cu,
+       tip, uucp, etc)? If not, read the section [208]DIALING OUT AND
+       COORDINATING WITH UUCP below.
+    z. Modem signals... Give a SET LINE command to a serial device and
+       then type the SHOW MODEM command. If it says "Modem signals
+       unavailable in this version of Kermit", then you might want to
+       look at the ttgmdm() routine in [209]ckutio.c and add the needed
+       code -- if indeed your version of Unix provides a way to get modem
+       signals (some don't; e.g. modem signals are a foreign concept to
+       POSIX, requiring politically incorrect workarounds).
+   aa. If it says "Modem signals unavailable", then it is likely that the
+       API for getting modem signals is provided, but it doesn't actually
+       do anything (e.g. ioctl(ttyfd,TIOCMGET,&x) returns EINVAL).
+   ab. In any case, it still should be able to manipulate the DTR signal.
+       To test, SET LINE , SET MODEM NONE, and HANGUP. The DTR light
+       should go out momentarily. If it doesn't, see if you can add the
+       needed code for your system to the tthang() routine in
+       [210]ckutio.c.
+   ac. If your version of Kermit has the SET FLOW RTS/CTS command, check
+       to see if it works: give Kermit this command, set your modem for
+       RTS/CTS, transfer some files (using big packet and window sizes)
+       and watch the RTS and CTS lights on the modem. If they go on and
+       off (and Kermit does not get packet errors), then it works. If
+       your version of Kermit does not have this command, but your
+       version of Unix does support hardware flow control, take a look at
+       the tthflow() command in [211]ckutio.c and see if you can add the
+       needed code (see the section on [212]HARDWARE FLOW CONTROL below).
+       (And please [213]send back any added code, so that others can
+       benefit from it and it can be carried forward into future
+       releases.)
+   ad. If C-Kermit starts normally and issues its prompt, echoing is
+       normal, etc, but then after returning from a CONNECT session, the
+       prompt no longer appears, try rebuilding with -DCKCONINTB4CB.
+   ae. (8.0.206 or later) Type some commands at the C-Kermit prompt. Can
+       you use the Up-arrow and Down-arrow keys on your keyboard to
+       access Kermit's command history? If not, and you're a programmer,
+       take a look at the USE_ARROWKEYS sections of ckucmd.c.
+  __________________________________________________________________________
+
+8. REDUCING THE SIZE OF THE EXECUTABLE PROGRAM IMAGE
+
+   [ [214]Top ] [ [215]Contents ] [ [216]Next ] [ [217]Previous ]
+
+   Also see: [218]C-Kermit Configuration Options
+
+    a. Many of C-Kermit's options and features can be deselected at
+       compile time. The greatest savings at the least sacrifice in
+       functionality is to disable the logging of debug information by
+       defining NODEBUG during compilation. See the [219]Configurations
+       Options document for further information.
+    b. Use shared libraries rather than static linking. This is the
+       default on many Unix systems anyway. However, executables built
+       for dynamic linking with shared libraries are generally not
+       portable away from the machine they were built on, so this is
+       recommended if the binary is for your use only.
+    c. Most Unix systems have a "strip" command to remove symbol table
+       information from an executable program image. "man strip" for
+       further information. The same effect can be achieved by including
+       "-s" among the link flags when building C-Kermit.
+    d. SCO, Interactive, and some other Unix versions have an "mcs"
+       command. "mcs -d wermit" can be used to delete the contents of the
+       ".comment" section from the executable program image.
+    e. Many modern optimizers can be instructed to optimize for space
+       rather than execution efficiency. Check the CFLAGS in the makefile
+       target, adjust as desired.
+  __________________________________________________________________________
+
+9. UNIX VERSIONS
+
+   [ [220]Top ] [ [221]Contents ] [ [222]Next ] [ [223]Previous ]
+
+   SECTION CONTENTS
+
+9.1 [224]Standards
+     9.1.1. [225]POSIX
+     9.1.2. [226]ANSI C
+     9.1.3. [227]Other Standards
+9.2. [228]Library Issues
+9.3. [229]Unix File System Peculiarities
+9.4. [230]Hardware Flow Control
+9.5. [231]Terminal Speeds
+9.6. [232]Millisecond Sleeps
+9.7. [233]Nondestructive Input Buffer Peeking
+9.8. [234]Other System-Dependent Features
+9.9. [235]Terminal Interruption
+
+   There are several major varieties of Unix: Bell Laboratories Seventh
+   Edition, AT&T System V, Berkeley Standard Distribution (BSD), and
+   POSIX. Each has many, many subvarieties and descendents, and there are
+   also hybrids that exhibit symptoms of two or more varieties, plus
+   special quirks of their own.
+
+   Seventh edition versions of C-Kermit include the compile-time option
+   -DV7 in the CFLAGS string in the makefile target. Various V7-based
+   implementations are also supported: -DCOHERENT, -DMINIX, etc.
+
+   AT&T-based versions of Unix Kermit include the compile-time option
+   -DATTSV (standing for AT&mp;T Unix System V). This applies to System
+   III and to System V up to and including Release 2. For System V
+   Release 3, the flag -DSVR3 should be used instead (which also implies
+   -DATTSV). This is because the data type of signal() and several other
+   functions was changed between SVR2 and SVR3. For System V Release 4,
+   include -DSVR4 because of changes in UUCP lockfile conventions; this
+   also implies -DSVR3 and -DATTSV.
+
+   For BSD, the flag -BSDxx must be included, where xx is the BSD version
+   number, for example BSD4 (for version 4.2 or later, using only 4.2
+   features), -DBSD41 (for BSD 4.1 only), -DBSD43 (for 4.3), -DBSD29 (BSD
+   2.9 for DEC PDP-11s). -DBSD44 is for 4.4BSD, which is the basis of
+   FreeBSD, NetBSD, OpenBSD, BSDI, and Mac OS X, and which contains many
+   POSIX features, and has little relation to 4.3BSD and earlier.
+
+   For POSIX, include the flag -DPOSIX. POSIX defines a whole new set of
+   terminal i/o functions that are not found in traditional AT&T or
+   Berkeley implementations, and also defines the symbol _POSIX_SOURCE,
+   which is used in many system and library header files, mainly to
+   disable non-POSIX (i.e. useful) features.
+
+   Note (circa 1997): In order to enable serial speeds higher than 38400
+   bps, it is generally necessary to add -DPOSIX (among other things),
+   since the older terminal APIs can not accommodate the new speeds --
+   out o' bits. But this often also means wholesale conversion to POSIX
+   APIs. In general, just try adding -DPOSIX and then see what goes
+   wrong. Be wary of features disappearing: when _POSIX_SOURCE is
+   defined, all sorts of things that were perfectly OK before suddenly
+   become politically incorrect -- like reading modem signals, doing
+   hardware flow control, etc. POSIX was evidently not designed with
+   serial communication in mind!
+
+   Case in point: In UnixWare 7.0, #define'ing POSIX causes strictness
+   clauses in the header files to take effect. These prevent <sys/time.h>
+   from defining the timeval and timezone structs, which are needed for
+   all sorts of things (like select()). Thus, if we want the high serial
+   speeds, we have to circumvent the POSIX clauses.
+
+   Similarly in SCO OpenServer R5.0.4 where, again, we must use the POSIX
+   APIs to get at serial speeds higher than 38400, but then doing so
+   removes hardware flow control -- just when we need it most! In cases
+   like this, dirty tricks are the only recourse (search for SCO_OSR504
+   in [236]ckutio.c for examples).
+
+   For reasons like this, Unix implementations tend to be neither pure
+   AT&T nor pure BSD nor pure POSIX, but a mixture of two or more of
+   these, with "compatibility features" allowing different varieties of
+   programs to be built on the same computer. In general, Kermit tries
+   not to mix and match but to keep a consistent repertoire throughout.
+   However, there are certain Unix implementations that only work when
+   you mix and match. For example, the Silicon Graphics IRIX operating
+   system (prior to version 3.3) is an AT&T Unix but with a BSD file
+   system. The only way you can build Kermit successfully for this
+   configuration is to include -DSVR3 plus the special option -DLONGFN,
+   meaning "pretend I was built with -DBSDxx when it's time to compile
+   file-related code". See the "iris" makefile target.
+    ________________________________________________________________________
+
+  9.1. Standards
+
+   [ [237]Top ] [ [238]Section Contents ] [ [239]Contents ] [ [240]Next ]
+
+   SUBSECTION CONTENTS
+
+9.1.1. [241]POSIX
+9.1.2. [242]ANSI C
+9.1.3. [243]Other Standards
+
+   In edits 166-167 (1988-89), C-Kermit was heavily modified to try to
+   keep abreast of new standards while still remaining compatible with
+   old versions of C and Unix. There are two new standards of interest:
+   ANSI C (as described in Kernighan and Ritchie, "The C Programming
+   Language", Second Edition, Prentice Hall, 1988) and POSIX.1 (IEEE
+   Standard 1003.1 and ISO/IEC 9945-1, 1990, "Portable Operating System
+   Interface"). These two standards have nothing to do with each other:
+   you can build C-Kermit with a non-ANSI compiler for a POSIX system, or
+   for a non-POSIX system with with an ANSI compiler.
+
+    9.1.1. POSIX
+
+   POSIX.1 defines a repertoire of system functions and header files for
+   use by C language programs. Most notably, the ioctl() function is not
+   allowed in POSIX; all ioctl() functions have been replaced by
+   device-specific functions like tcsetattr(), tcsendbreak(), etc.
+
+   Computer systems that claim some degree of POSIX compliance have made
+   some attempt to put their header files in the right places and give
+   them the right names, and to provide system library functions with the
+   right names and calling conventions. Within the header files,
+   POSIX-compliant functions are supposed to be within #ifdef
+   _POSIX_SOURCE..#endif conditionals, and non-POSIX items are not within
+   these conditionals.
+
+   If Kermit is built with neither -D_POSIX_SOURCE nor -DPOSIX, the
+   functions and header files of the selected version of Unix (or VMS,
+   etc) are used according to the CFLAGS Kermit was built with.
+
+   If Kermit is built with -D_POSIX_SOURCE but not -DPOSIX, then one of
+   the -DBSD or -DATTSV flags (or one that implies them) must also be
+   defined, but it still uses only the POSIX features in the system
+   header files. This allows C-Kermit to be built on BSD or AT&T systems
+   that have some degree of POSIX compliance, but still use BSD or AT&T
+   specific features.
+
+   The dilimma is this: it is often necessary to define _POSIX_SOURCE to
+   get at new or modern features, such as high serial speeds and the APIs
+   to deal with them. But defining _POSIX_SOURCE also hides other APIs
+   that Kermit needs, for example the ones dealing with modem signals
+   (others are listed just below). Thus all sorts of hideous contortions
+   are often required to get a full set of features.
+
+   The POSIX standard does not define anything about uucp lockfiles.
+   "make posix" uses NO (repeat, NO) lockfile conventions. If your
+   POSIX-compliant Unix version uses a lockfile convention such as
+   HDBUUCP (see below), use the "posix" entry, but include the
+   appropriate lockfile option in your KFLAGS on the "make" command line,
+   for example:
+
+make posix "KFLAGS=-DHDBUUCP"
+
+   POSIX.1 also lacks certain other features that Kermit needs. For
+   example:
+
+     * There is no defined way for an application to do wildcard matching
+       of filenames. Kermit uses the inode in the directory structure,
+       but POSIX.1 does not include this concept. (Later POSIX revisions
+       include functions named (I think) glob() and fnmatch(), but these
+       functions are not yet in Kermit, and might not be appropriate in
+       any case.)
+     * There is no POSIX mechanism for sensing or controlling modem
+       signals, nor to enable RTS/CTS or other hardware flow control.
+     * There is no select() for multiplexing i/o, and therefore no
+       TCP/IP.
+     * There is no way to check if characters are waiting in a
+       communications device (or console) input buffer, short of trying
+       to read them -- no select(), ioctl(fd,FIONREAD,blah), rdchk(),
+       etc. This is bad for CONNECT mode and bad for sliding windows.
+     * No way to do a millisecond sleep (no nap(), usleep(), select(),
+       etc).
+     * There is no popen().
+
+   So at this point, there cannot be one single fully functional POSIX
+   form of C-Kermit unless it also has "extensions", as do Linux, QNX,
+   etc.
+
+   More on POSIX (quoting from a newsgroup posting by Dave Butenhof):
+
+     Standards tend to look at themselves as "enabling". So POSIX
+     standards say that, in order to use POSIX functions, a program must
+     define some macro that will put the development environment in
+     "POSIX mode". For the ancient POSIX 1003.1-1990, the symbol is
+     _POSIX_SOURCE. For recent revisions, it's _POSIX_C_SOURCE with an
+     appropriate value. POSIX 1003.1-1996 says that, to use its features
+     in a portable manner, you must define _POSIX_C_SOURCE=199506L
+     before including any header files.
+
+     But for Solaris, or Digital Unix, the picture is different. POSIX
+     is one important but small part of the universe. Yet POSIX
+     unconditionally and unambiguously REQUIRES that, when
+     _POSIX_C_SOURCE=199506L, ALL of the functions and definitions
+     required by the standard, and NO others (except in specific
+     restricted namespaces, specifically "_" followed by an uppercase
+     letter or "__" followed by a lowercase letter) shall be visible.
+     That kinda puts a cramp on BSD and SVID support, because those
+     require names that are not in the "protected" POSIX namespaces.
+     It's ILLEGAL to make those symbols visible, unless you've done
+     something else that's beyond the scope of POSIX to allow the system
+     to infer that you didn't really mean it.
+
+     In most cases, you should just compile, with no standards-related
+     macros defined. The system will make available every interface and
+     definition that isn't incompatible with the "main stream". There
+     may indeed be cases where two standards cross, and you really can't
+     use both together. But, in general, they play nicely together as
+     long as you don't do anything rash -- like telling the system that
+     it's not allowed to let them.
+
+     In the area of threads, both Solaris and Digital Unix support
+     incompatible thread APIs. We have POSIX and DCE, they have POSIX
+     and UI. The nasty areas are in the _r routines and in some aspects
+     of signal behavior. You cannot compile a single source file that
+     uses both semantics. That's life. It sounds as if Solaris defaults
+     to the UI variants, but allows you to define this
+     _POSIX_THREAD_SEMANTICS to get around it. We default to POSIX, and
+     allow you to define _PTHREAD_USE_D4 (automatically defined by the
+     cc "-threads" switch) to select the DCE thread variants. That
+     default, because you're operating outside of any individual
+     standard, is really just a marketing decision.
+      ______________________________________________________________________
+
+    9.1.2. ANSI C
+
+   [ [244]Top ] [ [245]Contents ] [ [246]Section Contents ] [
+   [247]Subsection Contents ] [ [248]Next ] [ [249]Previous ]
+
+   The major difference between ANSI C and earlier C compilers is
+   function prototyping. ANSI C allows function arguments to be checked
+   for type agreement, and (when possible) type coercion in the event of
+   a mismatch. For this to work, functions and their arguments must be
+   declared before they are called. The form for function declarations is
+   different in ANSI C and non-ANSI C (ANSI C also accepts the earlier
+   form, but then does not do type checking).
+
+   As of edit 167, C-Kermit tries to take full advantage of ANSI C
+   features, especially function prototyping. This removes many bugs
+   introduced by differing data types used or returned by the same
+   functions on different computers. ANSI C features are automatically
+   enabled when the symbol __STDC__ is defined. Most ANSI C compilers,
+   such as GNU CC and the new DEC C compiler define this symbol
+   internally.
+
+   On the downside, ANSI C compilation increases the
+   administrative/bureacratic burden, spewing out countless unneeded
+   warnings about mismatched types, especially when we are dealing with
+   signed and unsigned characters, requiring casts everywhere to shut up
+   the mindless complaints -- there is no use for signed chars in Kermit
+   (or probably anywhere else). Some compilers, mercifully, include a
+   "treat all chars as unsigned" option, and when available it should be
+   used -- not only to stop the warnings, but also to avoid unhelpful
+   sign extension on high-bit characters.
+
+   To force use of ANSI C prototypes, include -DCK_ANSIC on the cc
+   command line. To disable the use of ANSI prototypes, include -DNOANSI.
+      ______________________________________________________________________
+
+    9.1.3. Other Standards
+
+   [ [250]Top ] [ [251]Contents ] [ [252]Section Contents ] [
+   [253]Subsection Contents ] [ [254]Next ] [ [255]Previous ]
+
+   As the years go by, standards with-which-all-must-comply continue to
+   pile up: AES, XPG2, XPG3, XPG4, FIPS 151-2, successive generations of
+   POSIX, OSF/1, X/Open, Spec 1170, UNIX95, Open Group UNIX98, ISO/IEC
+   9945 parts 1-4, ISO 9899, 88Open, OS 99, Single Unix Specification
+   (SUS, [256]IEEE 1003.1-2001, not to mention "mature standards" like
+   V7, 4.2/4.3BSD, System V R3 and R4 (SVID2 and SVID3), 4.4BSD (the
+   basis for BSDI, OpenBSD, NetBSD, FreeBSD, Mac OS X etc), /usr/group,
+   plus assorted seismic pronouncements of the neverending series of
+   ephemeral corporate consortia, not to mention the libc-vs-glibc
+   turmoil in the Linux arena and who knows what else.
+
+   None of these standards simplifies life for portable applications like
+   C-Kermit -- each one is simply one more environment to support (or
+   circumvent, as in many cases these standards do more harm than good by
+   denying access to facilities we need, e.g. as noted in above in
+   [257]9.1.1).
+    ________________________________________________________________________
+
+  9.2. Library Issues
+
+   [ [258]Top ] [ [259]Contents ] [ [260]Section Contents ] [
+   [261]Subsection Contents ] [ [262]Next ] [ [263]Previous ]
+
+   On most modern platforms, applications are -- and often must be --
+   dynamically linked. This has numerous advantages (smaller executables,
+   ability to patch a library and thereby patch all applications that use
+   it, etc), but also causes some headaches: most commonly, the library
+   ID built into the executable at link time does not match the ID of the
+   corresponding library on the target system, and so the loader refuses
+   to let the application run.
+
+   This problem only gets worse over time. In the Linux and *BSD world,
+   we also have totally different libraries (each with their own names
+   and numbering systems) that cover the same territory; for example,
+   curses vs ncurses, libc versus glibc. Combinations proliferate and any
+   given Unix computer might have any combination. For this reason it is
+   becoming increasingly difficult to produce a "Linux binary" for a
+   given architecture (e.g. PC or Alpha). There has to be a separate
+   binary for (at least) every combination of curses vs ncurses and libc
+   vs glibc.
+
+   In such cases, the best advice is for every user to build C-Kermit
+   from source code on the system where it will run. Too bad most
+   commercial Unix vendors have stopped including C compilers with the
+   operating system!
+    ________________________________________________________________________
+
+  9.3. Unix File System Peculiarities
+
+   [ [264]Top ] [ [265]Contents ] [ [266]Section Contents ] [ [267]Next ]
+   [ [268]Previous ]
+
+   Normally, including a BSD, System-V, POSIX, or DIRENT flag in the make
+   entry selects the right file system code. But some versions of Unix
+   are inconsistent in this regard, and building in the normal way either
+   gives compiler or linker errors, or results in problems at runtime,
+   typically failure to properly expand wildcard file specifications when
+   you do something like "send *.*", or failure to recognize long
+   filenames, as in "send filewithaveryveryveryveryverylongname".
+
+   C-Kermit is supposed to know about all the various styles of Unix file
+   systems, but it has to be told which one to use when you build it,
+   usually in the makefile target CFLAGS as shown below, but you might
+   also have to add something like -I/usr/include/bsd to CFLAGS, or
+   something like -lbsd to LIBS.
+
+   C-Kermit gives you the following CFLAGS switches to adapt to your file
+   system's peculiarities:
+
+-DDIRENT   - #include <dirent.h>
+-DSDIRENT  - #include <sys/dirent.h>
+-DNDIR     - #include <ndir.h>
+-DXNDIR    - #include <sys/ndir.h>
+-DRTU      - #include "/usr/lib/ndir.h", only if NDIR and XNDIR not defined.
+-DSYSUTIMH - #include <sys/utime.h> for setting file creation dates.
+-DUTIMEH   - #include <utime.h> for setting file creation dates.
+
+   (Note, RTU should only be used for Masscomp RTU systems, because it
+   also selects certain other RTU-specific features.)
+
+   If none of these is defined, then <sys/dir.h> is used. IMPORTANT: If
+   your system has the file /usr/include/dirent.h then be sure to add
+   -DDIRENT to your makefile target's CFLAGS. "dirent" should be used in
+   preference to any of the others, because it supports all the features
+   of your file system, and the others probably don't.
+
+   Having selected the appropriate directory header file, you might also
+   need to tell Kermit how to declare the routines and variables it needs
+   to read the directory. This happens most commonly on AT&T System-V
+   based UNIXes, particularly System V R3 and earlier, that provide long
+   file and directory names (longer than 14 characters). Examples include
+   certain releases of HP-UX, DIAB DNIX, older versions of Silicon
+   Graphics IRIX, and perhaps also MIPS. In this case, try adding
+   -DLONGFN to your makefile target.
+
+   Another problem child is <sys/file.h>. Most Unix C-Kermit versions
+   need to #include this file from within [269]ckufio.c and
+   [270]ckutio.c, but some not only do not need to include it, but MUST
+   not include it because (a) it doesn't exist, or (b) it has already
+   been included by some other header file and it doesn't protect itself
+   against multiple inclusion, or (c) some other reason that prevents
+   successful compilation. If you have compilation problems that seem to
+   stem from including this file, then add the following switch to CFLAGS
+   in your makefile target:
+
+-DNOFILEH
+
+   There are a few odd cases where <sys/file.h> must be included in one
+   of the cku[ft]io.c files, but not the other. In that case, add the
+   aforementioned switch, but go into the file that needs <sys/file.h>
+   and add something like this:
+
+#ifdef XXX       /* (where XXX is a symbol unique to your system) */
+#undef NOFILEH
+#endif /* XXX */
+
+   before the section that includes <sys/file.h>.
+
+   Kermit's SEND command expands wildcard characters "?" and "*" itself.
+   Before version 5A, commands like "send *" would send all regular
+   (non-directory) files, including "hidden files" (whose names start
+   with "."). In version 5A, the default behavior is to match like the
+   Bourne shell or the ls command, and not include files whose names
+   start with dot. Such files can still be sent if the dot is included
+   explicitly in the SEND command: "send .oofa, send .*". To change back
+   to the old way and let leading wildcard characters match dot files,
+   include the following in your CFLAGS:
+
+-DMATCHDOT
+
+   (In C-Kermit 6.0, there is also a command to control this at runtime.)
+
+   Complaints about data-type mismatches:
+
+     * If you get compile-time complaints about data type mismatches for
+       process-ID related functions like getpid(), add -DPID_T=pid_t.
+     * If you get compile-time complaints about data type mismatches for
+       user ID related functions like getuid(), add -DUID_T=uid_t.
+     * If you get compile-time complaints about data type mismatches for
+       user-ID related functions like getgid(), add -DGID_T=gid_t.
+     * If you get compile-time complaints about data type mismatches for
+       getpwuid(), add -DPWID_T=uid_t (or whatever it should be).
+
+   File creation dates: C-Kermit attempts to set the creation date/time
+   of an incoming file according to the date/time given in the file's
+   attribute packet, if any. If you find that the dates are set
+   incorrectly, you might need to build Kermit with the -DSYSUTIMEH flag,
+   to tell it to include <sys/utime.h>. If that doesn't help, look at the
+   code in zstrdt() in [271]ckufio.c.
+    ________________________________________________________________________
+
+  9.4. Hardware Flow Control
+
+   [ [272]Top ] [ [273]Contents ] [ [274]Section Contents ] [ [275]Next ]
+   [ [276]Previous ]
+
+   Hardware flow control is a problematic concept in many popular Unix
+   implementations. Often it is lacking altogether, and when available,
+   the application program interface (API) to it is inconsistent from
+   system to system. Here are some examples:
+
+    a. POSIX does not support hardware flow control.
+    b. RTS/CTS flow control support MIGHT be available for System V R3
+       and later if /usr/include/termiox.h exists (its successful
+       operation also depends on the device driver, and the device
+       itself, not to mention the cable, etc, actually supporting it). If
+       your SVR3-or-later Unix system does have this file, add:
+
+-DTERMIOX
+
+       to your CFLAGS. If the file is in /usr/include/sys instead, add:
+
+-DSTERMIOX
+
+       Note that the presence of this file does not guarantee that
+       RTS/CTS will actually work -- that depends on the device-driver
+       implementation (reportedly, many Unix versions treat
+       hardware-flow-control related ioctl's as no-ops).
+    c. Search ("grep -i") through /usr/include/*.h and
+       /usr/include/sys/*.h for RTS or CTS and see what turns up. For
+       example, in SunOS 4.x we find "CRTSCTS". Figuring out how to use
+       it is another question entirely! In IBM AIX RS/6000 3.x, we have
+       to "add" a new "line discipline" (and you won't find uppercase RTS
+       or CTS symbols in the header files).
+    d. NeXTSTEP and IRIX, and possibly others, support hardware flow
+       control, but do not furnish an API to control it, and thus on
+       these systems Kermit has no command to select it -- instead, a
+       special device name must be used. (NeXTSTEP: /dev/cufa instead of
+       /dev/cua; IRIX: /dev/ttyf00)
+
+   See the routine tthflow() in [277]ckutio.c for details. If you find
+   that your system offers hardware flow control selection under program
+   control, you can add this capability to C-Kermit as follows:
+
+    a. See if it agrees with one of the methods already used in
+       tthflow(). if not, add new code, appropriately #ifdef'd.
+    b. Add -DCK_RTSCTS to the compiler CFLAGS in your makefile target or
+       define this symbol within the appropriate #ifdefs in
+       [278]ckcdeb.h.
+
+   To illustrate the difficulties with RTS/CTS, here is a tale from Jamie
+   Watson <jw@adasoft.ch>, who added the RTS/CTS code for the RS/6000,
+   about his attempts to do the same for DEC ULTRIX:
+
+     "The number and type of hardware signals available to/from a serial
+     port vary between different machines and different types of serial
+     interfaces on each machine. This means that, for example, there are
+     virtually no hardware signals in or out available on the DECsystem
+     3000/3100 series; on the DECsystem 5000/2xx series all modem
+     signals in/out are present on both built-in serial ports; on the
+     DECsystem 5100 some ports have all signals and some only have some;
+     and so on... It looks to me as if this pretty well rules out any
+     attempt to use hardware flow control on these platforms, even if we
+     could figure out how to do it. The confusion on the user level
+     about whether or not it should work for any given platform or port
+     would be tremendous. And then it isn't clear how to use the
+     hardware signals even in the cases where the device supports them."
+    ________________________________________________________________________
+
+  9.5. Terminal Speeds
+
+   [ [279]Top ] [ [280]Contents ] [ [281]Section Contents ] [ [282]Next ]
+   [ [283]Previous ]
+
+   The allowable speeds for the SET SPEED command are defined in
+   [284]ckcdeb.h. If your system supports speeds that are not listed in
+   "set speed ?", you can add definitions for them to ckcdeb.h.
+
+   Then if the speed you are adding is one that was never used before in
+   Kermit, such as 921600, you'll also need to add the appropriate
+   keywords to spdtab[] in [285]ckuus3.c, and the corresponding case to
+   ttsspd() in [286]ckutio.c.
+    ________________________________________________________________________
+
+  9.6. Millisecond Sleeps
+
+   [ [287]Top ] [ [288]Contents ] [ [289]Section Contents ] [ [290]Next ]
+   [ [291]Previous ]
+
+   There is no standard for millisecond sleeps, but at least five
+   different functions have appeared in various Unix versions that can be
+   used for this purpose: nap() (mostly in System V), usleep() (found at
+   least in SunOS and NeXT OS), select() (found in 4.2BSD and later, and
+   part of any TCP/IP sockets library), nanosleep(), and sginap(). If you
+   have any of these available, pick one (in this order of preference, if
+   you have more than one):
+
+-DSELECT: Include this in CFLAGS if your system has the select() function.
+-DNAP:    Include this in CFLAGS if your system has the nap() function.
+-USLEEP:  Include this in CFLAGS if your system has the usleep() function.
+
+   NOTE: The nap() function is assumed to be a function that puts the
+   process to sleep for the given number of milliseconds. If your
+   system's nap() function does something else or uses some other units
+   of time (like the NCR Tower 32, which uses clock-ticks), do not
+   include -DNAP.
+
+   Reportedly, all versions of System V R4 for Intel-based computers, and
+   possibly also SVR3.2, include nap() as a kernel call, but it's not in
+   the library. To include code to use it via syscall(3112,x), without
+   having to include Xenix compatibility features, include the following
+   compile-time option:
+
+-DNAPHACK
+    ________________________________________________________________________
+
+  9.7. Nondestructive Input Buffer Peeking
+
+   [ [292]Top ] [ [293]Contents ] [ [294]Section Contents ] [ [295]Next ]
+   [ [296]Previous ]
+
+   Some AT&T Unix versions have no way to check if input is waiting on a
+   tty device, but this is a very important feature for Kermit. Without
+   it, sliding windows might not work very well (or at all), and you also
+   have to type your escape character to get Kermit's attention in order
+   to interrupt a local-mode file transfer. If your system offers an
+   FIONREAD ioctl, the build procedure should pick that up automatically
+   and use it, which is ideal.
+
+   If your system lacks FIONREAD but has a select() function, this can be
+   used instead. If the build procedure fails to include it (SHOW
+   FEATURES will list SELECT), then you can add it to your CFLAGS:
+
+-DSELECT
+
+   Conversely, if the build procedure tries to use select() when it
+   really is not there, add:
+
+-DNOSELECT
+
+   Note: select() is not part of System V nor of POSIX, but it has been
+   added to various System-V- and POSIX-based systems as an extension.
+
+   Some System-V variations (SCO Xenix/UNIX/ODT and DIAB DNIX) include a
+   rdchk() function that can be used for buffer peeking. It returns 0 if
+   no characters are waiting and 1 if characters are waiting (but unlike
+   FIONREAD, it does not tell the actual number). If your system has
+   rdchk(), add:
+
+-DRDCHK:  Include this in CFLAGS if your system has the rdchk() function.
+
+   Otherwise, if your version of Unix has the poll() function (and the
+   /usr/include/poll.h file) -- which appears to be a standard part of
+   System V going back to at least SVR3, include:
+
+-DCK_POLL
+    ________________________________________________________________________
+
+  9.8. Other System-Dependent Features
+
+   [ [297]Top ] [ [298]Contents ] [ [299]Section Contents ] [ [300]Next ]
+   [ [301]Previous ]
+
+   Systems with <termios.h> might have the symbol IEXTEN defined. This is
+   used to turn "extended features" in the tty device driver on and off,
+   such as Ctrl-O to toggle output flushing, Ctrl-V to quote input
+   characters, etc.
+
+   In most Unix implementations, it should be turned off during Kermit
+   operation, so if [302]ckutio.c finds this symbol, it uses it. This is
+   necessary, at least, on BSDI. On some systems, however, IEXTEN is
+   either misdefined or misimplemented. The symptom is that CR, when
+   typed to the command processor, is echoed as LF, rather than CRLF.
+   This happens (at least) on Convex/OS 9.1. The solution is to add the
+   following symbol to the makefile target's CFLACS:
+
+-DNOIEXTEN
+
+   However, in at least one Unix implementation, QNX 4.21, IEXTEN must be
+   set before hardware flow control can be used.
+
+   In edits 177 and earlier, workstation users noticed a "slow screen
+   writing" phenomenon during interactive command parsing. This was
+   traced to a setbuf() call in [303]ckutio.c that made console (stdout)
+   writes unbuffered. This setbuf() call has been there forever, and
+   could not be removed without some risk. Kermit's operation was tested
+   on the NeXT in edit 178 with the setbuf() call removed, and the
+   slow-writing symptom was cured, and everything else (command parsing,
+   proper wakeup on ?, ESC, Ctrl-U, and other editing characters,
+   terminal emulation, remote-mode and local-mode file transfer, etc)
+   seemed to work as well as or better than before. In subsequent edits,
+   this change was made to many other versions too, with no apparent ill
+   effects. To remove the setbuf() call for your version of Kermit, add:
+
+-DNOSETBUF
+
+   Later reports indicate that adding -DNOSETBUF has other beneficial
+   effects, like cutting down on swapping when Kermit is run on
+   workstations with small memories. But BEWARE: on certain small Unix
+   systems, notably the AT&T 6300 and 3B1 (the very same ones that
+   benefit from NOSETBUF), NOSETBUF seems to conflict with CK_CURSES. The
+   program builds and runs OK, but after once using the curses display,
+   echoing is messed up. In this case, we use a System-V specific
+   variation in the curses code, using newterm() to prevent System V from
+   altering the buffering. See makefile entries for AT&T 6300 and 3B1.
+
+   The Unix version of C-Kermit includes code to switch to file
+   descriptor zero (stdin) for remote-mode file transfer. This code is
+   necessary to prevent Kermit from giving the impression that it is
+   "idle" during file transfers, which, at some sites, can result in the
+   job being logged out in the middle of an active file transfer by
+   idle-job monitors.
+
+   However, this feature can interfere with certain setups; for example,
+   there is a package which substitutes a pty/tty pair for /dev/tty and
+   sets file descriptor 0 to be read-only, preventing Kermit from sending
+   packets. Or... When a Unix shell is invoked under the PICK
+   environment, file descriptor 0 is inoperative.
+
+   To remove this feature and allow Kermit to work in such environments,
+   add the compile-time option:
+
+-DNOFDZERO
+
+   On some versions of Unix, earlier releases of C-Kermit were reported
+   to render a tty device unusable after a hangup operation. Examples
+   include IBM AIX on the RT PC and RS/6000. A typical symptom of this
+   phenomenon is that the DIAL command doesn't work, but CONNECTing to
+   the device and dialing manually do work. A further test is to SET DIAL
+   HANGUP OFF, which should make dialing work once by skipping the
+   pre-dial hangup. However, after the connection is broken, it can't be
+   used any more: subsequent attempts to DIAL the same device don't work.
+   The cure is usually to close and reopen the device as part of the
+   hangup operation. To do this, include the following compile-time
+   option:
+
+-DCLSOPN
+
+   Similarly, there is a section of code in ttopen(), which does another
+   close(open()) to force the O_NDELAY mode change. On some systems, the
+   close(open()) is required to make the mode change take effect, and
+   apparently on most others it does no harm. But reportedly on at least
+   one System V R4 implementation, and on SCO Xenix 3.2, the
+   close(open()) operation hangs if the device lacks carrier, EVEN THOUGH
+   the CLOCAL characteristic has just been set to avoid this very
+   problem. If this happens to you, add this to your CFLAGS:
+
+-DNOCOTFMC
+
+   or, equivalently, in your KFLAGS on the make command line. It stands
+   for NO Close(Open()) To Force Mode Change.
+
+   C-Kermit renames files when you give a RENAME command and also
+   according to the current SET FILE COLLISION option when receiving
+   files. The normal Unix way to rename a file is via two system calls:
+   link() and unlink(). But this leaves open a window of vulnerability.
+   Some Unix systems also offer an atomic rename(oldname,newname)
+   function. If your version of Unix has this function, add the following
+   to your CFLAGS:
+
+-DRENAME
+
+   C-Kermit predefines the RENAME for several Unix versions in
+   [304]ckcdeb.h (SVR4, SUNOS41, BSD44, AIXRS, etc). You can tell if
+   rename() is being used if the SHOW FEATURES command includes RENAME in
+   the compiler options list. If the predefined RENAME symbol causes
+   trouble, then add NORENAME to your CFLAGS. Trouble includes:
+
+    a. Linker complains that _rename is an unresolved symbol.
+    b. Linking works, but Kermit's RENAME command doesn't work (which
+       happens because older versions of rename() might have their
+       arguments reversed).
+
+   If rename() is not used, then Kermit uses link()/unlink(), which is
+   equivalent except it is not atomic: there is a tiny interval in which
+   some other process might "do something" to one of the files or links.
+
+   Some Unix systems (Olivetti X/OS, Amdahl UTS/V, ICL SVR3, etc) define
+   the S_ISREG and S_ISDIR macros incorrectly. This is compensated for
+   automatically in [305]ckufio.c. Other systems might have this same
+   problem. If you get a compile-time error message regarding S_ISREG
+   and/or S_ISDIR, add the following to your CFLAGS:
+
+-DISDIRBUG
+
+   Finally, here's a symbol you should NEVER define:
+
+-DCOMMENT
+
+   It's used for commenting out blocks of code. If for some reason you
+   find that your compiler has COMMENT defined, then add -UCOMMENT to
+   CFLAGS or KFLAGS! Similarly, some header files have been known to
+   define COMMENT, in which case you must add "#undef COMMENT" to each
+   C-Kermit source module, after all the #includes.
+    ________________________________________________________________________
+
+  9.9. Terminal Interruption
+
+   [ [306]Top ] [ [307]Contents ] [ [308]Section Contents ] [ [309]Next ]
+   [ [310]Previous ]
+
+   When C-Kermit enters interactive command mode, it sets a Control-C
+   (terminal keyboard interrupt = SIGINT) trap to allow it to return to
+   the command prompt whenever the user types Control-C (or whatever is
+   assigned to be the interrupt character). This is implemented using
+   setjmp() and longjmp(). On some systems, depending on the machine
+   architecture and C compiler and who knows what else, you might get
+   "Memory fault (coredump)" or "longjmp botch" instead of the desired
+   effect (this should not happen in 5A(190) and later). In that case,
+   add -DNOCCTRAP to your CFLAGS and rebuild the program.
+
+   Job control -- the ability to "suspend" C-Kermit on a Unix system by
+   typing the "susp" character (normally Ctrl-Z) and then resume
+   execution later (with the "fg" command) -- is a tricky business.
+   C-Kermit must trap suspend signals so it can put the terminal back
+   into normal mode when you suspend it (Kermit puts the terminal into
+   various strange modes during interactive command parsing, CONNECT, and
+   file transfer). Supporting code is compiled into C-Kermit
+   automatically if <signal.h> includes a definition for the SIGTSTP
+   signal. HOWEVER... some systems define this signal without supporting
+   job control correctly. You can build Kermit to ignore SIGTSTP signals
+   by including the -DNOJC option in CFLAGS. (You can also do this at
+   runtime by giving the command SET SUSPEND OFF.)
+
+     NOTE: As of version 5A(190), C-Kermit makes another safety check.
+     Even if job control is available in the operating system (according
+     to the numerous checks made in congm()), it will still disable the
+     catching of SIGTSTP signals if SIGTSTP was set to SIG_IGN at the
+     time C-Kermit was started.
+
+   System V R3 and earlier systems normally do not support job control.
+   If you have an SVR3 system that does, include the following option in
+   your CFLAGS:
+
+-DSVR3JC
+
+   On systems that correctly implement POSIX signal handling, signals can
+   be handled more reliably than in Bell, Berkeley, or AT&T Unixes. On
+   systems (such as QNX) that are "strictly POSIX", POSIX signal handling
+   *must* be used, otherwise no signal will work more than once. If you
+   have POSIX-based system and you find that your version of Kermit
+   responds to Ctrl-C (SIGINT) or Ctrl-Z (SIGTSTP) only once, then you
+   should add the following option to your CFLAGS:
+
+-DCK_POSIX_SIG
+
+   But be careful; some POSIX implementations, notably 4.4BSD, include
+   POSIX signal handling symbols and functions as "stubs" only, which do
+   nothing. Look in <signal.h> for sigsetjmp and siglongjmp and read the
+   comments.
+  __________________________________________________________________________
+
+10. DIALING OUT AND COORDINATING WITH UUCP
+
+   [ [311]Top ] [ [312]Contents ] [ [313]Next ] [ [314]Previous ]
+
+     NOTE: Red Hat Linux 7.2 and later include a new API that allows
+     serial-port arbitration by non-setuid/gid programs. This API has
+     not yet been added to C-Kermit. If C-Kermit is to be used for
+     dialing out on Red Hat 7.2 or later, it must still be installed as
+     described in this section and the next. 
+
+   The short version:
+
+     In order for C-Kermit to be able to dial out from your Unix
+     computer, you need to give it the same owner, group, and
+     permissions as your other dialout programs, such as cu, tip,
+     minicom, uucp, seyon, etc.
+
+   The long version:
+
+   Make sure your dialout line is correctly configured for dialing out
+   (as opposed to login). The method for doing this is different for each
+   kind of Unix. Consult your system documentation for configuring lines
+   for dialing out (for example, Sun SPARCstation IPC users should read
+   the section "Setting up Modem Software" in the Desktop SPARC Sun
+   System and Network Manager's Guide, or the Terminals and Modems
+   section of the HP manual, "Configuring HP-UX for Peripherals" (e.g.
+   /usr/sbin/sam => Peripheral Devices => Terminals and Modems => Add
+   Modem).
+
+   Unlike most other multiuser, multitasking operating systems, Unix
+   allows multiple users to access the same serial device at the same
+   time, even though there is no earthly reason why two users should do
+   this. When they do, user A will read some of the incoming characters,
+   and user B will read the others. In all likelihood, neither user will
+   see them all. Furthermore, User B can hang up User A's call, etc.
+
+   Rather than change Unix to enforce exclusive access to serial devices
+   such as ttys, Unix developers chose instead to use a "lock file". Any
+   process that wants to open a tty device should first check to see if a
+   file of a certain name exists, and if so, not to open the device. If
+   the file does not exist, the process creates the file and then opens
+   the device. When the process closes the device, it destroys the
+   lockfile. This procedure was originated for use with Unix's UUCP, CU,
+   and TIP programs, and so these lockfiles are commonly called "UUCP
+   lockfiles" (UUCP = Unix-to-Unix Copy Program).
+
+   As you can imagine, this method is riddled with pitfalls:
+
+     * If a process does not observe the prevailing lockfile convention,
+       then it can interfere with other "polite" processes. And in fact,
+       very few Unix applications or commands handle lockfiles at all; an
+       original design goal of Unix was that "everything is a file", and
+       countless utilities operate on files directly (by opening them) or
+       indirectly through redirection of standard i/o, without creating
+       or looking for lockfiles.
+     * If a process crashes while it has the device open, the lockfile is
+       left behind, preventing further processes from using the device.
+     * Various versions of Unix use different names for the lockfiles,
+       put them in different directories, with different owners and
+       groups and permissions, and specify their contents differently.
+     * On a given platform, the lockfile conventions may change from one
+       Unix release to the next (for example, SunOS 4.0 to 4.1) or, in
+       the case of Linux, across different distributions.
+     * The same tty device might have more than one name, and most
+       lockfile conventions don't allow for this. Similarly for symbolic
+       links.
+
+   In an attempt to address the problem of "stale" lockfiles, most UUCP
+   implementations put the PID (Process ID) of the creating process in
+   the lockfile. Thus, another process that wants to open the
+   corresponding device can check not only for the lockfile itself, but
+   also can check the PID for validity. But this doesn't work well
+   either:
+
+     * PIDs are stored in diverse formats that change with every new
+       release (short, integer, long, or string in any of various
+       formats). If the reading program does not follow the same
+       convention as the writing program, it can diagnose a valid PID to
+       be invalid, and therefore not honor the lock.
+     * PIDs recycle. If the lockfile was created by PID 1234, which later
+       crashed without removing the lockfile, and then a new process 1234
+       exists a the time the lockfile is checked, the lockfile will be
+       improperly taken as valid, and access to the device denied
+       unnecessarily.
+
+   Several techniques address the problem of multiple names for the same
+   device:
+
+     * Multiple lockfiles. For example, if the user opens a device
+       through a symlink, a lockfile is created for both the symlink name
+       and the true name (obtained from readlink()). However, when
+       multiple drivers are installed for the same device (e.g. /dev/cua,
+       /dev/cufa, etc), this approach won't work unless all applications
+       *know* all the different names for the same device and make
+       lockfiles for all of them, which is obviously not practical.
+     * Lockfiles whose names are not based on the device name. These
+       lockfiles generally have names like LK.inode/major/minor, where
+       inode, major, and minor are numbers, which will always be the same
+       for any physical device, no matter what its name. This form of
+       lockfile is used in System V R4 and its derivatives, such as
+       Solaris, UnixWare, etc. If lockfiles must be used (as opposed to,
+       say, kernel-based locks), this would seem to be the most effective
+       form.
+
+   Most versions of Unix were not designed to accommodate third-party
+   communications software; thus vendors of these Unix products feel no
+   compunction about changing lockfile conventions from release to
+   release, since they also change their versions of the cu, uucp, tip,
+   etc, programs at the same time to match. And since the source code to
+   these programs might not be published, it is difficult for makers of
+   third-party products like C-Kermit to find out what the new
+   conventions are. It also forces release of new versions of C-Kermit
+   whenever the OS vendor makes a change like this.
+
+   Some Unix vendors have taken a small step to simplify communications
+   application development for their products: the inclusion of lockfile
+   routines in the standard system C runtime libraries to shield the
+   application from the details of lockfile management (IBM AIX is an
+   example). When such routines are used, communications applications do
+   not need modification when lockfile conventions change (although they
+   will need recompiling if the routines are statically linked into the
+   application). In the AIX example, the simple function calls ttylock(),
+   ttyunlock(), and ttylocked() replace hundreds of lines of ugly code in
+   C-Kermit that attempts to keep pace with every release of every Unix
+   product over the last 20 years. Inclusion of ttylock() code occurs
+   when:
+
+-DUSETTYLOCK
+
+   is included in the CFLAGS.
+
+   If such routines are available, they should be used. The rest of this
+   section applies when they are not.
+
+   To fit in with UUCP and other Unix-based communication software,
+   C-Kermit must have the same idea as your system's uucp, cu, and tip
+   programs about what the UUCP lock directory is called, what the
+   lockfile itself is called, and what its contents should be. In most
+   cases, C-Kermit preprocessor flags create the appropriate
+   configuration at compile time if the appropriate makefile target was
+   used (see [315]ckutio.c). The following CFLAGS options can be used to
+   override the built-in configuration:
+
+   -DLCKDIR
+          Tells Kermit that the UUCP lock directory is
+          /usr/spool/uucp/LCK.
+
+   -DACUCNTRL
+          Tells Kermit to use the BSD 4.3 acucntrl() program to turn off
+          getty (login) on the line before using it, and restore getty
+          when done.
+
+   -DHDBUUCP
+          Include this if your system uses Honey DanBer UUCP, in which
+          the lockfile directory and format are relatively standardized.
+
+   -DLOCK_DIR=\\\"/xxx/yyy\\\"
+          Gives the lock directory name explicitly. The triple quoting is
+          necessary. For example:
+
+CFLAGS= -DBSD4 -DLOCK_DIR=\\\"/usr/local/locks\\\" -DNODEBUG
+
+          (NOTE: The triple quoting assumes this is a "top-level" make
+          entry, and not a make entry that calls another one.)
+
+   -DLFDEVNO The lockfile name uses the tty device inode and major and
+          minor
+          numbers: LK.dev.maj.min, as in Sys V R4, e.g. LK.035.044.008.
+
+   When the LK.inode.major.minor form is used, a single lockfile is
+   enough. Otherwise, a single lockfile rarely suffices. For example, in
+   Linux, it is common to have a /dev/modem symbolic link to an actual
+   dialout device, like /dev/cua0 or /dev/ttyS0, whose purpose is to hide
+   the details of the actual driver from the user. So if one user opens
+   /dev/modem, a lockfile called LCK..modem is created, which does not
+   prevent another user from simulataneously opening the same device by
+   its real name.
+
+   On SCO Unix platforms, we have a slightly different problem: the same
+   device is, by convention, known by "lowercase" and "uppercase" names,
+   depending on whether it has modem control. So by convention,
+   communications programs are supposed to create the lockfiles based on
+   the lowercase name. But some programs don't follow this convention. In
+   HP-UX, we have several different names for each serial device. And so
+   on.
+
+   For this reason, on platforms where the LK.inode.major.minor form is
+   not used, C-Kermit also creates a secondary lockfile (which is simply
+   a link to the first) if:
+
+    a. The given device name is a symbolic link. The secondary link is
+       based on the device's real name.
+    b. On SCO: The device name is not a symbolic link, but it contains
+       uppercase letters. The primary link is based on the lowercase
+       name; the secondary link is based on the name that was given.
+    c. On HP-UX: The device name starts with "cu". The primary link is
+       based on the name that was given; the secondary link is based on
+       the corresponding "ttyd" device, e.g. "LCK..cua0p0" and
+       "LCK..ttyd0p0".
+
+   NOTE: symlinks are not handled in HP-UX.
+
+   Honey DanBer (HDB) UUCP, which is becoming increasingly popular, has
+   two characteristics:
+
+    a. Lockfiles are kept in /usr/spool/locks/ (usually).
+    b. A lockfile contains the process id (pid) in ASCII, rather than as
+       an int.
+
+   Non-HDB selections assume the lockfile contains the pid in int form
+   (or, more precisely, in PID_T form, where PID_T is either int or
+   pid_t, depending on your system's C library and header files). (b), by
+   the way, is subject to interpretation: the numeric ASCII string may or
+   may not be terminated by a newline, it may or may not have leading
+   spaces (or zeros), and the number of leading spaces or zeros can
+   differ, and the differences can be significant.
+
+   Even if you build the program with the right lockfile option, you can
+   still have problems when you try to open the device. Here are the
+   error messages you can get from SET LINE, and what they mean:
+
+    a. "Timed out, no carrier." This one is not related to lockfiles. It
+       means that you have SET CARRIER ON xx, where xx is the number of
+       seconds to wait for carrier, and carrier did not appear within xx
+       seconds. Solution: SET CARRIER AUTO or OFF.
+    b. "Sorry, access to lock denied." Kermit has been configured to use
+       lockfiles, but (a)the lockfile directory is write-protected
+       against you, or (b) it does not exist. The "access to lock denied"
+       message will tell you the reason. If the directory does not exist,
+       check to make sure Kermit is using the right name. Just because
+       version n of your Unix used a certain lockfile directory is no
+       gurantee that version n.1 does not use a different one.
+       Workaround: ask the system administrator to install a symbolic
+       link from the old name to the new name. Other solutions: (see
+       below)
+    c. "Sorry, access to tty device denied." The tty device that you
+       specified in your SET LINE command is read/write protected against
+       you. Solution: (see below)
+    d. "Sorry, device is in use." The tty device you have specified is
+       currently being used by another user. A prefatory message gives
+       you an "ls -l" listing of the lockfile, which should show the
+       username of the person who created it, plus a message "pid = nnn"
+       to show you the process id of the user's program. Solutions: try
+       another device, wait until the other user is finished, ask the
+       other user to hurry up, or ask the system manager for help.
+    e. "Sorry, can't open connection: reason". The device cannot be
+       opened for some other reason, which is listed.
+    f. "sh: /usr/lib/uucp/acucntrl: not found". This means your Kermit
+       program was built with the -DACUCNTRL switch, but your computer
+       system does not have the BSD 4.3 acucntrl program. Solution:
+       install the acucntrl program if you have it, or rebuild Kermit
+       without the -DACUCNTRL switch.
+
+   There are two solutions for problems (b) and (c), both of which
+   involve intervention by your Unix system administrator (superuser):
+
+    a. Have the superuser change the permission of the lockfile directory
+       and to the tty devices so that everyone on the system has
+       read/write permission.
+
+su% chmod 777 /usr/spool/locks (or whatever the path is)
+su% chmod 666 /dev/ttyXX
+
+       One risk here is that people can write lots of junk into the
+       lockfile directory, delete other people's files in the lockfile
+       directory, and intercept other people's data as it goes in and out
+       of the tty device. The major danger here would be intercepting a
+       privileged password. Of course, any user could write a short,
+       ordinary, unprivileged program to do exactly the same thing if the
+       tty device was world read/writeable. The other risk as that
+       telephone calls are not controlled -- anybody on your system can
+       make them, without having to belong to any particular group, and
+       this could run up your phone bill.
+    b. Use groups to regulate access. Normally the lockfile directory and
+       and the dialout devices will have the same group (such as uucp).
+       If so, then put everybody who's allowed to dial out into that
+       group, and make sure that the lockfile directory and the tty
+       devices have group read AND write permission. Example:
+
+su% chmod 770 /usr/spool/locks (or whatever the path is)
+su% chmod 660 /dev/ttyXX
+
+       User whatever tool is available on your platform to add users to
+       the appropropriate group (e.g. edit the /etc/group file).
+    c. Have the superuser change Kermit to run setuid and/or setgid to
+       the owner and/or group of the lockfile directory and the tty
+       devices if necessary), typically uucp (see [316]next section), but
+       NOT root. Example:
+
+su% chown uucp kermit          - or -  chgrp uucp kermit
+su% chmod u+s kermit (setuid)  - or -  chmod g+s kermit (setgid)
+
+       and then make sure the lockfile directory, and the tty devices,
+       have owner (setuid) and/or group (setgid) write permission. For
+       example:
+
+su% chmod o+rwx /usr/spool/uucp
+su% chown uucp /dev/ttyXX ; chmod 600 /dev/ttyXX
+
+       In some cases, the owner and group must be distinct; the key point
+       is that read/write access is required to both the UUCP lockfile
+       directory and the tty itself.
+
+   If you make C-Kermit setuid or setgid to root, it refuses to run:
+
+Fatal: C-Kermit setuid to root!
+
+   Example:
+
+crw-r-----   1 uucp     uucp       5,  67 Feb 11 06:23 /dev/cua3
+drwxrwxr-x   3 root     uucp         1024 Feb 11 06:22 /var/lock
+
+   requires suid uucp to get read/write access on /dev/cua3 and sgid to
+   get read/write access on /var/lock (since you can't set Kermit's uid
+   or gid to root).
+
+     The reason Kermit can't be setuid or setgid to root has to do with
+     the fact that some Unix OS's can't switch user or group IDs in that
+     case. Unfortunately, the prohibition against making Kermit setuid
+     or setgid to root means that Unix C-Kermit can't be used to make
+     rlogin connections by non-root users. (The rlogin port is
+     privileged, which is why the regular rlogin command is setuid root
+     -- which is safe because the rlogin program never has to create or
+     access files like Kermit does.)
+
+   For the lockfile mechanism to achieve its desired purpose --
+   prevention of access to the same tty device by more than one process
+   at a time -- ALL programs on a given computer that open, read or
+   write, and close tty devices must use the SAME lockfile conventions.
+   Unfortunately, this is often not the case. Here is a typical example
+   of how this can go wrong: In SunOS 4.0 and earler, the lockfile
+   directory was /usr/spool/uucp; in 4.1 it was changed to
+   /var/spool/locks in the quest for political correctness. Consequently,
+   any third-party programs (such as C-Kermit) that were not modified to
+   account for this change, recompiled, and reinstalled, did not use the
+   same lockfiles as uucp, tip, etc, and so the entire purpose of the
+   lockfile is defeated.
+
+   What if your Unix system does not have UUCP installed? For example,
+   you have a Unix workstation, and you do not use uucp, cu, or tip, or
+   UUCP was not even supplied with your version of Unix (QNX is an
+   example). In this case, you have two choices:
+
+    a. If there may be more than one person running Kermit at the same
+       time, competing for the same tty device, then create a special
+       lockfile directory just for Kermit, for example,
+       /usr/spool/kermit, and make sure you have read/write access to it.
+       Then add the following to your makefile target CFLAGS, as shown
+       earlier:
+
+-DLOCK_DIR=\\\"/usr/spool/kermit\\\"
+
+    b. If you are the only user on your workstation, and no other
+       processes will ever be competing with Kermit for the dialout tty
+       device, then add -DNOUUCP to your makefile target's CFLAGS and
+       rebuild Kermit.
+  __________________________________________________________________________
+
+11. RUNNING UNIX C-KERMIT SETUID OR SETGID
+
+   [ [317]Top ] [ [318]Contents ] [ [319]Next ] [ [320]Previous ]
+
+   Even if you don't intend to run C-Kermit setuid, somebody else might
+   come along and chown and chmod it after it has been built. You should
+   be sure that it is built correctly to run setuid on your system. For
+   POSIX and AT&T Unix based versions, you don't have to do anything
+   special.
+
+   For 4.2 and 4.3 BSD-based Unix versions, you normally need not add
+   anything special to the makefile. The program assumes that the
+   setreuid() and setregid() functions are available, without which we
+   cannot switch back and forth between real and effective uids. If
+   "make" complains that _setreuid or _setregid is/are not defined, add
+   -DNOSETREU to CFLAGS. In this case it is very likely (but not certain)
+   that you cannot protect ttys and lockfiles against people and have
+   them run Kermit setuid.
+
+   If make does not complain about this, you should find out whether your
+   BSD version (4.3 or other systems like SunOS 4.x that claim to include
+   BSD 4.3 compatibility) includes the saved-setuid feature (see long
+   notes under edit 146 in ckc178.upd). If it does, then add -DSAVEDUID
+   to CFLAGS.
+
+     IMPORTANT NOTE: Most Unix system documentation will not give you
+     the required information. To determine whether your Unix system
+     supplies the the saved-original-effective-user/group-id feature,
+     use the ckuuid.c program. Read and follow the instructions in the
+     comments at the beginning.
+
+   C-Kermit for 4.4BSD-based systems automatically use sete[ug]id(). See
+   [321]ckutio.c.
+
+   If you have a version of Unix that is not BSD-based, but which
+   supplies the setreuid() and setregid() functions, and these are the
+   only way to switch between real and effective uid, add -DSETREUID to
+   your makefile target.
+
+     WARNING: There are two calls to access() in [322]ckufio.c, by which
+     Kermit checks to see if it can create an output file. These calls
+     will not work correctly when (a)you have installed C-Kermit setuid
+     or setgid on a BSD-based Unix system, and (b) the
+     saved-original-effective-uid/gid feature is not present, and (c)
+     the access() function always checks what it believes to be the real
+     ID rather than the effective ID. This is the case, for example, in
+     Olivetti X/OS and in NeXTSTEP. In such cases, you can force correct
+     operation of access() calls by defining the symbol SW_ACC_ID at
+     compile time in CFLAGS.
+
+   If you have a version of Unix that does not allow a process to switch
+   back and forth between its effective and real user and group ids
+   multiple times, you probably should not attempt to run Kermit setuid,
+   because once having given up its effective uid or gid (which it must
+   do in order to transfer files, fork a shell, etc) it can never get it
+   back, and so it can not use the original effective uid or gid to
+   create or delete uucp lockfiles. In this case, you'll either have to
+   set the permissions on your lockfile directory to make them publicly
+   read/writable, or dispense with locking altogether.
+
+   MORAL: Are you thoroughly sickened and/or frightened by all that you
+   have just read? You should be. What is the real answer? Simple. Serial
+   devices -- such as ttys and magnetic tapes -- in Unix should be opened
+   with exclusive access only, enforced by the Unix kernel. Shared access
+   has no conceivable purpose, legitimate or otherwise, except by
+   privileged system programs such as getty. The original design dates
+   from the late 1960s, when Unix was developed for laboratory use under
+   a philosophy of trust by people within shouting distance of each other
+   -- but even then, no useful purpose was served by this particular form
+   of openness; it was probably more of a political statement. Since the
+   emergence of Unix from the laboratory into the commercial market, we
+   have seen every vestige of openness -- but this one -- stripped away.
+   I'd like to see some influential Unix maker take the bold step of
+   making the simple kernel change required to enforce exclusive access
+   to serial devices. (Well, perhaps not so simple when bidirectionality
+   must also be a goal -- but then other OS's like VMS solved this
+   problem decades ago.)
+  __________________________________________________________________________
+
+12. CONFIGURING UNIX WORKSTATIONS
+
+   [ [323]Top ] [ [324]Contents ] [ [325]Next ] [ [326]Previous ]
+
+   On desktop workstations that are used by only the user at the console
+   keyboard, C-Kermit is always used in local mode. But as delivered,
+   C-Kermit runs in remote mode by default. To put it in local mode at
+   startup, you can put a SET LINE command in your .mykermrc.
+
+   You can also build C-Kermit to start up in local mode by default. To
+   do this, include the following in the CFLAGS in your makefile target:
+
+-DDFTTY=\\\"/dev/ttyxx\\\"
+
+   where ttyxx is the name of the device you will be using for
+   communications. Presently there is no way of setting the default modem
+   type at compile time, so use this option only for direct lines.
+
+   C-Kermit does not work well on certain workstations if it is not run
+   from within a terminal window. For example, you cannot start C-Kermit
+   on a NeXT by launching it directly from NeXTstep. Similarly for Sun
+   workstations in the Open Windows environment. Run Kermit in a terminal
+   window.
+  __________________________________________________________________________
+
+13. BIZARRE BEHAVIOR AT RUNTIME
+
+   [ [327]Top ] [ [328]Contents ] [ [329]Next ] [ [330]Previous ]
+
+   See the "beware file",
+
+   [331]ckubwr.txt, for hints about runtime misbehavior. This section
+   lists some runtime problems that can be cured by rebuilding C-Kermit.
+
+   The program starts, but there is no prompt, and certain operations
+   don't work (you see error messages like "Kermit command error in
+   background execution"). This is because Kermit thinks it is running in
+   the background. See conbgt() in [332]ckutio.c. Try rebuilding Kermit
+   with:
+
+ -DPID_T=pid_t
+
+   added to your CFLAGS. If that doesn't help, find out the actual data
+   type for pids (look in types.h or similar file) and use it in place of
+   "pid_t", for example:
+
+ -DPID_T=short
+
+   Unexplainable and inappropriate error messages ("Sockets not supported
+   on this device", etc) have been traced in at least one case to a lack
+   of agreement between the system header files and the actual kernel.
+   This happened because the GNU C compiler (gcc) was being used. gcc
+   wants to have ANSI-C-compliant header files, and so part of the
+   installation procedure for gcc is (or was) to run a shell script
+   called "fixincludes", which translates the system's header files into
+   a separate set of headers that gcc likes. So far so good. Later, a new
+   version of the operating system is installed and nobody remembers to
+   run fixincludes again. From that point, any program compiled with gcc
+   that makes use of header files (particularly ioctl.h) is very likely
+   to misbehave. Solution: run fixincludes again, or use your system's
+   regular C compiler, libraries, and header files instead of gcc.
+  __________________________________________________________________________
+
+14. CRASHES AND CORE DUMPS
+
+   [ [333]Top ] [ [334]Contents ] [ [335]Next ] [ [336]Previous ]
+
+   If C-Kermit constitently dumps core at the beginning of a file
+   transfer, look in SHOW FEATURES for CKREALPATH. If found, rebuild with
+   -DNOREALPATH and see if that fixes the problem (some UNIXes have
+   realpath() but it doesn't work).
+
+   Total failure of the Kermit program can occur because of bad memory
+   references, bad system calls, or problems with dynamic memory
+   allocation. First, try to reproduce the problem with debugging turned
+   on: run Kermit with the -d command-line option (for example, "wermit
+   -d") and then examine the resulting debug.log file. The last entry
+   should be in the vicinity of the crash. In VMS, a crash automatically
+   produces a "stack dump" which shows the routine where the crash
+   occurs. In some versions of Unix, you can get a stack dump with "adb"
+   -- just type "adb wermit core" and then give the command "$c", then
+   Ctrl-D to quit (note: replace "wermit" by "kermit" or by the full
+   pathname of the executable that crashed if it is not in the current
+   directory). Or use gdb to get a backtrace, etc.
+
+   In edit 186, one implementation, UNISYS 5000/95 built with "make
+   sys5r3", has been reported to run out of memory very quickly (e.g.
+   while executing a short initialization file that contains a SET DIAL
+   DIRECTORY command). Debug logs show that malloc calls are failing,
+   reason unknown. For this and any other implementation that gives error
+   messages about "malloc failure" or "memory allocation failure",
+   rebuild the program *without* the -DDYNAMIC CFLAGS definition, for
+   example:
+
+make sys5r3 KFLAGS=-UDYNAMIC
+
+   As of edit 169, C-Kermit includes a malloc() debugging package which
+   you may link with the Kermit program to catch runtime malloc errors.
+   See the makefile entries for sunos41md and nextmd for examples of how
+   to select malloc debugging. Once you have linked Kermit with the
+   malloc debugger, it will halt with an informative message if a
+   malloc-related error occurs and, if possible, dump core. For this
+   reason, malloc-debugging versions of Kermit should be built without
+   the "-s" link option (which removes symbols, preventing analysis of
+   the core dump). You have several ways to track down the malloc error:
+   Analyze the core dump with adb. Or reproduce the problem with "log
+   debug" and then look at the code around the last debug.log entry. If
+   you have gcc, build the program with "-g" added to CFLAGS and then
+   debug it with gdb, e.g.
+
+gdb wermit
+break main
+run
+.. set other breakpoints or watchpoints
+continue
+
+   Watchpoints are especially useful for finding memory leaks, but they
+   make the program run about a thousand times slower than usual, so
+   don't set them until the last possible moment. When a watchpoint is
+   hit, you can use the "where" command to find out which C-Kermit source
+   statement triggered it.
+
+   If you have the Pure Software Inc "Purify" product, see the sunos41cp
+   makefile entry for an example of how to use it to debug C-Kermit.
+  __________________________________________________________________________
+
+15. SYSLOGGING
+
+   [ [337]Top ] [ [338]Contents ] [ [339]Next ] [ [340]Previous ]
+
+   "Syslogging" means recording selected in the system log via the Unix
+   syslog() facility, which is available in most Unix versions.
+   Syslogging is not done unless C-Kermit is started with:
+
+--syslog:n
+
+   on the command-line, where n is a number greater than 0 to indicate
+   the level of syslogging. See [341]Section 4.2 of the [342]IKSD
+   Administrator's Guide for details.
+
+   Obviously you can't depend on users to include --syslog:3 (or
+   whatever) on the command line every time they start C-Kermit, so if
+   you want certain kinds of records to be recorded in the system log,
+   you can build C-Kermit with forced syslogging at the desired level,
+   e.g.:
+
+make linux KFLAGS=-DSYSLOGLEVEL=2
+
+   Levels 2 and 3 are the most likely candidates for this treatment.
+   Level 2 forces logging of all successful dialout calls (e.g. for
+   checking against or phone bills), and level 3 records all connections
+   (SET LINE or SET HOST / TELNET / RLOGIN, etc) so you can see who is
+   connecting out from your system, and to where.
+
+   Level 2 and 3 records are equivalent to those in the connection log;
+   see the [343]C-Kermit 7.0 Supplement) for a detailed description of
+   the connection log.
+  __________________________________________________________________________
+
+16. BUILDING SECURE VERSIONS OF C-KERMIT 8.0
+
+   [ [344]Top ] [ [345]Contents ] [ [346]Next ] [ [347]Previous ]
+
+   C-Kermit 7.0 and later may be built with Kerberos(TM) and/or SRP(TM)
+   (Secure Remote Password) and/or SSL/TLS security for strong
+   authentication and encryption of Internet connections. These security
+   methods require external libraries that, in their binary forms, are
+   restricted from export by USA law. See the [348]Kermit Security
+   Reference) for details. C-Kermit binaries themselves are likewise
+   restricted; the C-Kermit binaries that are available for public
+   download on the Internet are not allowed to contain the security
+   options.
+
+   Sample makefile entries are provided for Linux and many other
+   operating systems. A list of secure makefile entries is included in
+   the Makefile. Complete instructions on building C-Kermit 8.0 with MIT
+   Kerberos; Secure Remote Password; and/or OpenSSL can be found in the
+   [349]Kermit Security Reference.
+
+   C-Kermit 8.0 comes with a current list of Certificate Authority
+   certificates, including one for the Kermit Project that can be used
+   for authentication to Columbia's [350]Internet Kermit Service (IKSD).
+   You can use C-Kermit 7.0 or later to access Columbia's IKSD securely
+   by installing the Kermit Project certificate in
+   /usr/local/ssl/cert.pem (or the appropriate location based upon the
+   installation of OpenSSL on your system). You can find a copy of the
+   certificates file at:
+
+[351]ftp://kermit.columbia.edu/kermit/c-kermit/ca_certs.pem
+  __________________________________________________________________________
+
+17. INSTALLING C-KERMIT AS AN SSH SERVER SUBSYSTEM
+
+   [ [352]Top ] [ [353]Contents ] [ [354]Previous ]
+
+   This requires C-Kermit 8.0.206 or later and an SSH v2 server. If you
+   list C-Kermit as a Subsystem in the SSH v2 server configuration file
+   (as, for example, SFTP is listed), users can make SSH connections
+   direct to a Kermit server as explained here:
+
+[355]http://www.columbia.edu/kermit/skermit.html
+
+   The name and location of the SSH server configuration file depends on
+   your platform, which SSH product(s) you have, etc. C-Kermit itself
+   must be referred to in this file as "kermit-sshsub". On the host,
+   install the C-Kermit 8.0.211 binary in the normal way. Then, in the
+   same directory as the C-Kermit binary, make a symbolic link:
+
+ln -s kermit kermit-sshsub
+
+   (Note: the "make install" makefile target does this for you.) Then in
+   the sshd configuration file, add a line:
+
+Subsystem  kermit   /some/path/kermit-sshsub
+
+   (where /some/path is the fully specified directory where the symlink
+   is.) This is similar to the line that sets up the SFTP susbsystem.
+   Example:
+
+Subsystem   sftp    /usr/local/libexec/sftp-server
+Subsystem   kermit  /usr/local/bin/kermit-sshsub
+
+   The mechanics might vary for other SSH servers; "man sshd" for
+   details. The method shown here is used because the OpenSSH server does
+   not permit the subsystem invocation to include command-line options.
+   C-Kermit would have no way of knowing that it should enter Server mode
+   if it were not called by a special name.
+
+   [ [356]Top ] [ [357]Contents ] [ [358]C-Kermit Home ] [ [359]C-Kermit
+   8.0 Overview ] [ [360]Kermit Home ]
+     _________________________________________________________________
+
+
+    C-Kermit 8.0 Unix Installation Instructions / The Kermit Project /
+    Columbia University / 10 April 2004
+
+References
+
+   1. http://www.columbia.edu/kermit/ckuins.html#contents
+   2. http://www.columbia.edu/kermit/ckermit.html
+   3. http://www.columbia.edu/kermit/index.html
+   4. http://www.columbia.edu/kermit/ckuins.html
+   5. http://www.columbia.edu/kermit/ckuins.html#x0
+   6. http://www.columbia.edu/kermit/ckuins.html#x1
+   7. http://www.columbia.edu/kermit/ckuins.html#x2
+   8. http://www.columbia.edu/kermit/ckuins.html#x3
+   9. http://www.columbia.edu/kermit/ckuins.html#x4
+  10. http://www.columbia.edu/kermit/ckuins.html#x5
+  11. http://www.columbia.edu/kermit/ckuins.html#x6
+  12. http://www.columbia.edu/kermit/ckuins.html#x7
+  13. http://www.columbia.edu/kermit/ckuins.html#x8
+  14. http://www.columbia.edu/kermit/ckuins.html#x9
+  15. http://www.columbia.edu/kermit/ckuins.html#x10
+  16. http://www.columbia.edu/kermit/ckuins.html#x11
+  17. http://www.columbia.edu/kermit/ckuins.html#x12
+  18. http://www.columbia.edu/kermit/ckuins.html#x13
+  19. http://www.columbia.edu/kermit/ckuins.html#x14
+  20. http://www.columbia.edu/kermit/ckuins.html#x15
+  21. http://www.columbia.edu/kermit/ckuins.html#x16
+  22. http://www.columbia.edu/kermit/ckuins.html#x16
+  23. http://www.columbia.edu/kermit/ckuins.html#top
+  24. http://www.columbia.edu/kermit/ckuins.html#contents
+  25. http://www.columbia.edu/kermit/ckuins.html#x1
+  26. http://www.columbia.edu/kermit/ckccfg.html
+  27. http://www.columbia.edu/kermit/ckcbwr.html
+  28. http://www.columbia.edu/kermit/ckubwr.html
+  29. http://www.columbia.edu/kermit/ckcplm.html
+  30. http://www.columbia.edu/kermit/ckuins.html#x2
+  31. http://www.columbia.edu/kermit/x3
+  32. http://www.columbia.edu/kermit/ckuins.html#x4
+  33. http://www.columbia.edu/kermit/ckuins.html#top
+  34. http://www.columbia.edu/kermit/ckuins.html#contents
+  35. http://www.columbia.edu/kermit/ckuins.html#x2
+  36. http://www.columbia.edu/kermit/ckuins.html#x0
+  37. ftp://kermit.columbia.edu/kermit/archives/cku211.tar.Z
+  38. ftp://kermit.columbia.edu/kermit/archives/cku211.tar.gz
+  39. ftp://kermit.columbia.edu/kermit/archives/cku211.tar
+  40. http://www.columbia.edu/kermit/ckuins.html#x7
+  41. http://www.columbia.edu/kermit/ckuins.html#x5
+  42. http://www.columbia.edu/kermit/ckuins.html#x5
+  43. http://www.columbia.edu/kermit/ckuins.html#x16
+  44. http://www.columbia.edu/kermit/ckuins.html#top
+  45. http://www.columbia.edu/kermit/ckuins.html#contents
+  46. http://www.columbia.edu/kermit/ckuins.html#x3
+  47. http://www.columbia.edu/kermit/ckuins.html#x1
+  48. http://www.columbia.edu/kermit/ckuins.html#x5
+  49. http://www.columbia.edu/kermit/ckuins.html#X10
+  50. http://www.columbia.edu/kermit/ckuins.html#x11
+  51. http://www.columbia.edu/kermit/ckuins.html#x10
+  52. http://www.columbia.edu/kermit/ckuins.html#x3
+  53. http://www.columbia.edu/kermit/ck80packages.html
+  54. http://www.columbia.edu/kermit/ckuins.html#x10
+  55. http://www.columbia.edu/kermit/ckuins.html#top
+  56. http://www.columbia.edu/kermit/ckuins.html#contents
+  57. http://www.columbia.edu/kermit/ckuins.html#x4
+  58. http://www.columbia.edu/kermit/ckuins.html#x2
+  59. ftp://kermit.columbia.edu/kermit/bin/
+  60. http://www.columbia.edu/kermit/ck80binaries.html
+  61. http://www.columbia.edu/kermit/ckuins.html#x7
+  62. http://www.columbia.edu/kermit/ckuins.html#build
+  63. http://www.columbia.edu/kermit/ckuins.html#x5
+  64. http://www.columbia.edu/kermit/ckuins.html#x4
+  65. http://www.columbia.edu/kermit/ckuins.html#x4
+  66. mailto:kermit@columbia.edu
+  67. http://www.columbia.edu/kermit/ckuins.html#top
+  68. http://www.columbia.edu/kermit/ckuins.html#contents
+  69. http://www.columbia.edu/kermit/ckuins.html#x5
+  70. http://www.columbia.edu/kermit/ckuins.html#x3
+  71. http://www.columbia.edu/kermit/ckuins.html#x8
+  72. http://www.columbia.edu/kermit/ckuins.html#x9
+  73. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+  74. ftp://kermit.columbia.edu/kermit/c-kermit/ckpker.mk
+  75. ftp://kermit.columbia.edu/kermit/c-kermit/ckubsd.mak
+  76. http://www.columbia.edu/kermit/ckuins.html#x5
+  77. mailto:kermit-support@columbia.edu
+  78. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+  79. http://www.columbia.edu/kermit/ckuins.html#x7
+  80. mailto:kermit-support@columbia.edu
+  81. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+  82. http://www.columbia.edu/kermit/ckuins.html#x5.4
+  83. http://www.columbia.edu/kermit/ckuins.html#x10
+  84. http://www.columbia.edu/kermit/ckuins.html#x11
+  85. http://www.columbia.edu/kermit/ckuins.html#x5
+  86. http://www.columbia.edu/kermit/iksd.html
+  87. http://www.columbia.edu/kermit/ckuins.html#top
+  88. http://www.columbia.edu/kermit/ckuins.html#contents
+  89. http://www.columbia.edu/kermit/ckuins.html#x4.1
+  90. http://www.columbia.edu/kermit/ckccfg.html
+  91. http://www.columbia.edu/kermit/ckuins.html#x4.1
+  92. http://www.columbia.edu/kermit/ckuins.html#x4.2
+  93. http://www.columbia.edu/kermit/ckuins.html#x4.3
+  94. http://www.columbia.edu/kermit/ckuins.html#x4.4
+  95. http://www.columbia.edu/kermit/ckuins.html#x4.5
+  96. http://www.columbia.edu/kermit/ckccfg.html
+  97. http://www.columbia.edu/kermit/ckccfg.html#x8
+  98. http://www.columbia.edu/kermit/iksd.html
+  99. http://www.columbia.edu/kermit/iksd.html
+ 100. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 101. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 102. mailto:kermit-support@columbia.edu
+ 103. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
+ 104. http://www.columbia.edu/kermit/ckuins.html#x15
+ 105. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 106. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 107. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 108. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 109. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
+ 110. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
+ 111. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 112. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.c
+ 113. mailto:kermit-support@columbia.edu
+ 114. http://www.columbia.edu/kermit/ckuins.html#top
+ 115. http://www.columbia.edu/kermit/ckuins.html#contents
+ 116. http://www.columbia.edu/kermit/ckuins.html#x4
+ 117. http://www.columbia.edu/kermit/ckuins.html#x4.2
+ 118. http://www.columbia.edu/kermit/ckuins.html#x4.0
+ 119. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 120. ftp://kermit.columbia.edu/kermit/c-kermit/ckubwr.txt
+ 121. http://www.columbia.edu/kermit/ckubwr.html
+ 122. ftp://kermit.columbia.edu/kermit/c-kermit/ckwart.c
+ 123. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+ 124. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.c
+ 125. http://www.columbia.edu/kermit/ckuins.html#top
+ 126. http://www.columbia.edu/kermit/ckuins.html#contents
+ 127. http://www.columbia.edu/kermit/ckuins.html#x4
+ 128. http://www.columbia.edu/kermit/ckuins.html#x4.3
+ 129. http://www.columbia.edu/kermit/ckuins.html#x4.1
+ 130. http://www.columbia.edu/kermit/ckuins.html#x5
+ 131. http://www.columbia.edu/kermit/ckuins.html#top
+ 132. http://www.columbia.edu/kermit/ckuins.html#contents
+ 133. http://www.columbia.edu/kermit/ckuins.html#x4
+ 134. http://www.columbia.edu/kermit/ckuins.html#x4.4
+ 135. http://www.columbia.edu/kermit/ckuins.html#x4.2
+ 136. http://www.columbia.edu/kermit/ckuins.html#top
+ 137. http://www.columbia.edu/kermit/ckuins.html#contents
+ 138. http://www.columbia.edu/kermit/ckuins.html#x4
+ 139. http://www.columbia.edu/kermit/ckuins.html#x4.5
+ 140. http://www.columbia.edu/kermit/ckuins.html#x4.3
+ 141. ftp://kermit.columbia.edu/kermit/c-kermit/ckpker.mk
+ 142. http://www.columbia.edu/kermit/ckuins.html#top
+ 143. http://www.columbia.edu/kermit/ckuins.html#contents
+ 144. http://www.columbia.edu/kermit/ckuins.html#x4
+ 145. http://www.columbia.edu/kermit/ckuins.html#x4.4
+ 146. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 147. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 148. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
+ 149. http://www.columbia.edu/kermit/ckuins.html#top
+ 150. http://www.columbia.edu/kermit/ckuins.html#contents
+ 151. http://www.columbia.edu/kermit/ckuins.html#x6
+ 152. http://www.columbia.edu/kermit/ckuins.html#x4
+ 153. http://www.columbia.edu/kermit/ckuins.html#x5.1
+ 154. http://www.columbia.edu/kermit/ckuins.html#x5.2
+ 155. http://www.columbia.edu/kermit/ckuins.html#x5.3
+ 156. http://www.columbia.edu/kermit/ckuins.html#x5.4
+ 157. http://www.columbia.edu/kermit/
+ 158. http://www.columbia.edu/kermit/ckuins.html#x5.4
+ 159. http://www.columbia.edu/kermit/ckuins.html#x5.3
+ 160. ftp://kermit.columbia.edu/kermit/c-kermit/COPYING.TXT
+ 161. ftp://kermit.columbia.edu/kermit/c-kermit/ckermit.ini
+ 162. http://www.columbia.edu/kermit/ckuins.html#x5.1
+ 163. ftp://kermit.columbia.edu/kermit/c-kermit/ckermod.ini
+ 164. ftp://kermit.columbia.edu/kermit/c-kermit/ckermit70.txt
+ 165. http://www.columbia.edu/kermit/ck60manual
+ 166. http://www.columbia.edu/kermit/ckermit70.html
+ 167. ftp://kermit.columbia.edu/kermit/c-kermit/ckermit80.txt
+ 168. http://www.columbia.edu/kermit/ck60manual
+ 169. http://www.columbia.edu/kermit/ckermit80.html
+ 170. ftp://kermit.columbia.edu/kermit/c-kermit/ckcbwr.txt
+ 171. http://www.columbia.edu/kermit/ckcbwr.html
+ 172. ftp://kermit.columbia.edu/kermit/c-kermit/ckubwr.txt
+ 173. http://www.columbia.edu/kermit/ckubwr.html
+ 174. ftp://kermit.columbia.edu/kermit/c-kermit/ckuins.txt
+ 175. http://www.columbia.edu/kermit/ckuins.html
+ 176. ftp://kermit.columbia.edu/kermit/c-kermit/ckccfg.txt
+ 177. http://www.columbia.edu/kermit/ckccfg.html
+ 178. ftp://kermit.columbia.edu/kermit/c-kermit/ckcplm.txt
+ 179. http://www.columbia.edu/kermit/ckcplm.html
+ 180. ftp://kermit.columbia.edu/kermit/c-kermit/ca_certs.pem
+ 181. http://www.columbia.edu/kermit/ckuins.html#x16"
+ 182. ftp://kermit.columbia.edu/kermit/c-kermit/makefile
+ 183. http://www.columbia.edu/kermit/ckuins.html#x?
+ 184. http://www.columbia.edu/kermit/ckuins.html#x11
+ 185. http://www.columbia.edu/kermit/ckuins.html#x5.2
+ 186. http://www.columbia.edu/kermit/ckermit.html#download
+ 187. http://www.columbia.edu/kermit/ck80binaries.html
+ 188. http://www.columbia.edu/kermit/ckermit.html#download
+ 189. http://www.columbia.edu/kermit/ckuins.html#top
+ 190. http://www.columbia.edu/kermit/ckuins.html#contents
+ 191. http://www.columbia.edu/kermit/ckuins.html#x7
+ 192. http://www.columbia.edu/kermit/ckuins.html#x5
+ 193. http://www.columbia.edu/kermit/ckuins.html#top
+ 194. http://www.columbia.edu/kermit/ckuins.html#contents
+ 195. http://www.columbia.edu/kermit/ckuins.html#x8
+ 196. http://www.columbia.edu/kermit/ckuins.html#x6
+ 197. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 198. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 199. http://www.columbia.edu/kermit/ckuins.html#x4.0
+ 200. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 201. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 202. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 203. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 204. http://www.columbia.edu/kermit/ckuins.html#x10
+ 205. http://www.columbia.edu/kermit/ckccfg.html#x2
+ 206. http://www.columbia.edu/kermit/ckccfg.html
+ 207. http://www.columbia.edu/kermit/ckuins.html#x4
+ 208. http://www.columbia.edu/kermit/ckuins.html#x10
+ 209. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 210. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 211. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 212. http://www.columbia.edu/kermit/ckuins.html#x9.4
+ 213. mailto:kermit-support@columbia.edu
+ 214. http://www.columbia.edu/kermit/ckuins.html#top
+ 215. http://www.columbia.edu/kermit/ckuins.html#contents
+ 216. http://www.columbia.edu/kermit/ckuins.html#x9
+ 217. http://www.columbia.edu/kermit/ckuins.html#x7
+ 218. http://www.columbia.edu/kermit/ckccfg.html
+ 219. http://www.columbia.edu/kermit/ckccfg.html
+ 220. http://www.columbia.edu/kermit/ckuins.html#top
+ 221. http://www.columbia.edu/kermit/ckuins.html#contents
+ 222. http://www.columbia.edu/kermit/ckuins.html#x10
+ 223. http://www.columbia.edu/kermit/ckuins.html#x8
+ 224. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 225. http://www.columbia.edu/kermit/ckuins.html#x9.1.1
+ 226. http://www.columbia.edu/kermit/ckuins.html#x9.1.2
+ 227. http://www.columbia.edu/kermit/ckuins.html#x9.1.3
+ 228. http://www.columbia.edu/kermit/ckuins.html#x9.2
+ 229. http://www.columbia.edu/kermit/ckuins.html#x9.3
+ 230. http://www.columbia.edu/kermit/ckuins.html#x9.4
+ 231. http://www.columbia.edu/kermit/ckuins.html#x9.5
+ 232. http://www.columbia.edu/kermit/ckuins.html#x9.6
+ 233. http://www.columbia.edu/kermit/ckuins.html#x9.7
+ 234. http://www.columbia.edu/kermit/ckuins.html#x9.8
+ 235. http://www.columbia.edu/kermit/ckuins.html#x9.9
+ 236. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 237. http://www.columbia.edu/kermit/ckuins.html#top
+ 238. http://www.columbia.edu/kermit/ckuins.html#x9
+ 239. http://www.columbia.edu/kermit/ckuins.html#contents
+ 240. http://www.columbia.edu/kermit/ckuins.html#x9.2
+ 241. http://www.columbia.edu/kermit/ckuins.html#x9.1.1
+ 242. http://www.columbia.edu/kermit/ckuins.html#x9.1.2
+ 243. http://www.columbia.edu/kermit/ckuins.html#x9.1.3
+ 244. http://www.columbia.edu/kermit/ckuins.html#top
+ 245. http://www.columbia.edu/kermit/ckuins.html#contents
+ 246. http://www.columbia.edu/kermit/ckuins.html#x9
+ 247. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 248. http://www.columbia.edu/kermit/ckuins.html#x9.1.3
+ 249. http://www.columbia.edu/kermit/ckuins.html#x9.1.1
+ 250. http://www.columbia.edu/kermit/ckuins.html#top
+ 251. http://www.columbia.edu/kermit/ckuins.html#contents
+ 252. http://www.columbia.edu/kermit/ckuins.html#x9
+ 253. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 254. http://www.columbia.edu/kermit/ckuins.html#x9.2
+ 255. http://www.columbia.edu/kermit/ckuins.html#x9.1.2
+ 256. http://www.opengroup.org/onlinepubs/007904975/
+ 257. http://www.columbia.edu/kermit/ckuins.html#x9.1.1
+ 258. http://www.columbia.edu/kermit/ckuins.html#top
+ 259. http://www.columbia.edu/kermit/ckuins.html#contents
+ 260. http://www.columbia.edu/kermit/ckuins.html#x9
+ 261. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 262. http://www.columbia.edu/kermit/ckuins.html#x9.3
+ 263. http://www.columbia.edu/kermit/ckuins.html#x9.1
+ 264. http://www.columbia.edu/kermit/ckuins.html#top
+ 265. http://www.columbia.edu/kermit/ckuins.html#contents
+ 266. http://www.columbia.edu/kermit/ckuins.html#x9
+ 267. http://www.columbia.edu/kermit/ckuins.html#x9.4
+ 268. http://www.columbia.edu/kermit/ckuins.html#x9.2
+ 269. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 270. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 271. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 272. http://www.columbia.edu/kermit/ckuins.html#top
+ 273. http://www.columbia.edu/kermit/ckuins.html#contents
+ 274. http://www.columbia.edu/kermit/ckuins.html#x9
+ 275. http://www.columbia.edu/kermit/ckuins.html#x9.5
+ 276. http://www.columbia.edu/kermit/ckuins.html#x9.3
+ 277. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 278. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 279. http://www.columbia.edu/kermit/ckuins.html#top
+ 280. http://www.columbia.edu/kermit/ckuins.html#contents
+ 281. http://www.columbia.edu/kermit/ckuins.html#x9
+ 282. http://www.columbia.edu/kermit/ckuins.html#x9.6
+ 283. http://www.columbia.edu/kermit/ckuins.html#x9.4
+ 284. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 285. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus3.c
+ 286. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 287. http://www.columbia.edu/kermit/ckuins.html#top
+ 288. http://www.columbia.edu/kermit/ckuins.html#contents
+ 289. http://www.columbia.edu/kermit/ckuins.html#x9
+ 290. http://www.columbia.edu/kermit/ckuins.html#x9.7
+ 291. http://www.columbia.edu/kermit/ckuins.html#x9.5
+ 292. http://www.columbia.edu/kermit/ckuins.html#top
+ 293. http://www.columbia.edu/kermit/ckuins.html#contents
+ 294. http://www.columbia.edu/kermit/ckuins.html#x9
+ 295. http://www.columbia.edu/kermit/ckuins.html#x9.8
+ 296. http://www.columbia.edu/kermit/ckuins.html#x9.6
+ 297. http://www.columbia.edu/kermit/ckuins.html#top
+ 298. http://www.columbia.edu/kermit/ckuins.html#contents
+ 299. http://www.columbia.edu/kermit/ckuins.html#x9
+ 300. http://www.columbia.edu/kermit/ckuins.html#x9.9
+ 301. http://www.columbia.edu/kermit/ckuins.html#x9.7
+ 302. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 303. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 304. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
+ 305. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 306. http://www.columbia.edu/kermit/ckuins.html#top
+ 307. http://www.columbia.edu/kermit/ckuins.html#contents
+ 308. http://www.columbia.edu/kermit/ckuins.html#x9
+ 309. http://www.columbia.edu/kermit/ckuins.html#x10
+ 310. http://www.columbia.edu/kermit/ckuins.html#x9.8
+ 311. http://www.columbia.edu/kermit/ckuins.html#top
+ 312. http://www.columbia.edu/kermit/ckuins.html#contents
+ 313. http://www.columbia.edu/kermit/ckuins.html#x11
+ 314. http://www.columbia.edu/kermit/ckuins.html#x9
+ 315. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 316. http://www.columbia.edu/kermit/ckuins.html#x11
+ 317. http://www.columbia.edu/kermit/ckuins.html#top
+ 318. http://www.columbia.edu/kermit/ckuins.html#contents
+ 319. http://www.columbia.edu/kermit/ckuins.html#x12
+ 320. http://www.columbia.edu/kermit/ckuins.html#x10
+ 321. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 322. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
+ 323. http://www.columbia.edu/kermit/ckuins.html#top
+ 324. http://www.columbia.edu/kermit/ckuins.html#contents
+ 325. http://www.columbia.edu/kermit/ckuins.html#x13
+ 326. http://www.columbia.edu/kermit/ckuins.html#x11
+ 327. http://www.columbia.edu/kermit/ckuins.html#top
+ 328. http://www.columbia.edu/kermit/ckuins.html#contents
+ 329. http://www.columbia.edu/kermit/ckuins.html#x14
+ 330. http://www.columbia.edu/kermit/ckuins.html#x12
+ 331. ftp://kermit.columbia.edu/kermit/c-kermit/ckubwr.txt
+ 332. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
+ 333. http://www.columbia.edu/kermit/ckuins.html#top
+ 334. http://www.columbia.edu/kermit/ckuins.html#contents
+ 335. http://www.columbia.edu/kermit/ckuins.html#x15
+ 336. http://www.columbia.edu/kermit/ckuins.html#x13
+ 337. http://www.columbia.edu/kermit/ckuins.html#top
+ 338. http://www.columbia.edu/kermit/ckuins.html#contents
+ 339. http://www.columbia.edu/kermit/ckuins.html#x16
+ 340. http://www.columbia.edu/kermit/ckuins.html#x14
+ 341. http://www.columbia.edu/kermit/iksd.html#x4.2
+ 342. http://www.columbia.edu/kermit/iksd.html
+ 343. http://www.columbia.edu/kermit/ckermit2.html
+ 344. http://www.columbia.edu/kermit/ckuins.html#top
+ 345. http://www.columbia.edu/kermit/ckuins.html#contents
+ 346. http://www.columbia.edu/kermit/ckuins.html#x17
+ 347. http://www.columbia.edu/kermit/ckuins.html#x15
+ 348. http://www.columbia.edu/kermit/security.html
+ 349. http://www.columbia.edu/kermit/security80.html
+ 350. http://www.columbia.edu/kermit/cuiksd.html
+ 351. ftp://kermit.columbia.edu/kermit/c-kermit/ca_certs.pem
+ 352. http://www.columbia.edu/kermit/ckuins.html#top
+ 353. http://www.columbia.edu/kermit/ckuins.html#contents
+ 354. http://www.columbia.edu/kermit/ckuins.html#x16
+ 355. http://www.columbia.edu/kermit/skermit.html
+ 356. http://www.columbia.edu/kermit/ckuins.html#top
+ 357. http://www.columbia.edu/kermit/ckuins.html#contents
+ 358. http://www.columbia.edu/kermit/ckermit.html
+ 359. http://www.columbia.edu/kermit/ck80.html
+ 360. http://www.columbia.edu/kermit/index.html
diff --git a/ckermit-8.0.211/ckuker.nr b/ckermit-8.0.211/ckuker.nr
new file mode 100644
index 0000000..b26801d
--- /dev/null
+++ b/ckermit-8.0.211/ckuker.nr
@@ -0,0 +1,1827 @@
+.\" @(#) kermit.1 8.0.211 2004/04/10 Columbia University
+.TH KERMIT 1 "APRIL 2004" "User Manuals"
+.na
+.SH NAME
+kermit \-
+.B C-Kermit 8.0:
+transport- and platform-independent
+interactive and scriptable communications software.
+.IP
+
+This document is intended to give the beginner sufficient information to make
+basic (if not advanced) use of C-Kermit 8.0.  Although it might be rather long
+for a Unix manual page, it's still far shorter than the C-Kermit manual, which
+should be consulted for advanced topics such as customization, character-sets,
+scripting, etc. We also attempt to provide a clear structural overview of
+C-Kermit'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 8.0 from earlier releases.
+.PP
+This document is also available as a Web page at:
+.IP
+http://www.columbia.edu/kermit/ckututor.html
+.SH DESCRIPTION
+C-Kermit is an all-purpose communications software package from the Kermit
+Project at Columbia University that:
+.PP
+.nf
+\(bu	Is portable to many platforms, Unix and non-Unix 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-file file transfer.
+.br
+\(bu	Is customizable in every aspect of its operation.
+.fi
+.PP
+C-Kermit is a modem program, a Telnet client, an Rlogin 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-approved 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-end file-transfer 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-Kermit, can be "scripted" (automated) using its built-in
+cross-platform transport-independent script programming language, which
+happens to be identical to its interactive command language.
+.PP
+This manual page offers an overview of C-Kermit 8.0 for Unix ("Unix" is an
+operating system family that includes AIX, DG/UX, FreeBSD, HP-UX, 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-Kermit
+manual and supplements (see DOCUMENTATION below). For further information
+about C-Kermit, Kermit software for other platforms, and Kermit manuals,
+visit the Kermit Project website:
+.PP
+  http://www.columbia.edu/kermit/
+.PP
+This is a longer-than-average manual page, and yet it barely scratches the
+surface. Don't be daunted. C-Kermit 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-line argument is the name of a file, interactive-mode
+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-line 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-line URL (if any, and if so, execution stops here).
+.TP
+ 5.
+Command-line options (if any).
+.TP
+ 6.
+Interactive commands.
+.PP
+Some command-line 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-Kermit can be built with selected features
+disabled, and also that certain features are not available on all
+platforms. For example, C-Kermit 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 lacks
+C-Kermit a feature mentioned here, use its SHOW FEATURES command to
+see what might have been excluded.
+.PP
+C-Kermit has three kinds of commands: regular single-letter command-line
+options, extended-format command-line options, and interactive commands.
+.PP
+Like most Unix commands, C-Kermit can be be given options on the command
+line. But C-Kermit also can be used interactively by giving it commands
+composed of words, which are more intuitive than cryptic command-line
+options, and more flexible too. In other words, you don't have to use
+C-Kermit's command-line options, but they are available if you want to. (By
+the same token, you don't have to use its interactive commands either --
+you can use either or both in any combination.)
+.PP
+C-Kermit 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-line
+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-Kermit's single-letter command-line 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-the-middle" operation: 8 bits, no parity, no
+escape character, everything passes through.
+.TP
+-8
+(digit eight)  Connection is 8-bit clean (this is the
+default in C-Kermit 8.0). 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-address-or-hostname[:optional-TCP-port].
+NOTE: C-Kermit also has a separate FTP command-line
+personality, with regular FTP-like command-line
+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-mode 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-Kermit also has a
+separate Telnet command-line personality, with regular Telnet-like
+command-line 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, Rlogin, 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-Kermit 7.0 and later.
+.TP
+-R
+Remote-only (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-file text/binary switching.
+Equivalent to SET TRANSFER MODE MANUAL.
+.TP
+-Y
+Skip (don't execute) the initialization file.
+.TP
+-a arg
+As-name for file(s) in -s, -r, or -g.
+Argument: As-name 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-transfer
+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-letter command-line 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-duplex 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). Equivalanet 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-line options (necessary because single-letter 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-to 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-level 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-Kermit prints its version number.
+.PP
+Plus several other IKSD-Only options described at:
+.PP
+  http://www.columbia.edu/kermit/iksd.html
+.PP
+See the file-transfer section for examples of command-line invocation.
+.SH COMMAND LANGUAGE
+C-Kermit's interactive command language is the subject of a 622-page 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-Kermit'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-level 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 oofa.txt
+.PP
+which tells Kermit to send (transfer) the file whose name is oofa.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-Kermit 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-in and user-defined
+functions, string manipulation, pattern matching, block structure, scoping,
+recursion, and all the rest. To get a list of all C-Kermit'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 (\). If you need to include a
+literal backslash in a command, type two of them, e.g.:
+.PP
+  get c:\ek95\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). Please don't pipe a
+command file into Kermit's standard input (which might or might not work);
+if you have Kermit commands in a file, tell Kermit to TAKE the 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-in
+variable (xxx is the variable name, "home" in this case). To see what
+built-in variables are available, type "show variables" at the C-Kermit
+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-Kermit has more than 200 top-level 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-level 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-level help.
+.TP
+HELP command
+Requests help about the given command.
+.TP
+INTRODUCTION
+Requests a brief introduction to C-Kermit.
+.TP
+LICENSE
+Displays the C-Kermit software copyright and license.
+.TP
+VERSION
+Displays C-Kermit's version number.
+.TP
+EXIT [ number ]
+Exits from Kermit with the given
+status code. Synonyms: QUIT, E, Q.
+.TP
+TAKE filename [ parameters... ]
+Executes commands from the given
+.TP
+LOG item [ filename ]
+Keeps a log of the given item 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-and/or-time ]
+Shows current date-time or interprets given date-time.
+.TP
+RUN [ extern-command [ parameters... ]                 
+Runs the given external command. Synonym: !.
+.TP
+EXEC [ extern-command [ 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-in, 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
+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
+SSH [ options ] host
+Opens an SSH connection to the host and enters Connect state.
+.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-command
+Runs the command on a pseudoterminal as if it were a connection.
+.TP
+PIPE external-command
+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-level 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-state escape character.
+.RE
+.SS
+Closing Connections
+.RS
+.TP
+HANGUP
+Hangs up the currently open
+serial-port or network connection.
+.TP
+CLOSE
+Closes the currently open
+serial-port or network connection.
+.TP
+SET LINE (with no devicename)
+Closes the currently open
+serial-port or network connection.
+.TP
+SET HOST (with no hostname)
+Closes the currently open serial-port 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-name ]
+Sends the given file. Synonym: S.
+.TP
+SEND [ options ] filespec
+Sends all files that match.
+.TP
+RESEND [ options ] filespec
+Resumes an interupted SEND from the point of failure.
+.TP
+RECEIVE [ options ] [ as-name ]                    
+Waits passively for files to arrive. Synonym: R.
+.TP
+LOG TRANSACTIONS [ filename ]
+Keeps a record of file transfers.
+.TP
+FAST
+Use fast file-transfer settings (default).
+.TP
+CAUTIOUS
+Use cautious and less fast file-transfer settings.
+.TP
+ROBUST
+Use ultra-conservative and slow file-transfer 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-transfer 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-name ]                   
+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 interupted SEND from the point of failure.
+.TP
+GET [ options ] remote-filespec
+Asks the server to send the given files. Synonym: G.
+.TP
+REGET [ options ] remote-filespec
+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-mail (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-Kermit executes commands from a file 
+called .kermrc in your home directory when it starts, unless it is given the
+-Y or -y command-line option. Custom configurations might substitute a shared
+system-wide 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-Kermit 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 -- 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-Kermit
+directly when you don't.
+.PP
+To put it another way... We still distribute the standard initialization
+file since it's featured in the manual and backwards compatibility is
+important to us. But there's no harm in not using it if you don't need the
+stuff that's in it (services directory, dialing directory, network
+directory, and associated macro definitions). On the other hand, if there
+are settings or macros you want in effect EVERY time you use Kermit, the
+initialization file (or the customization file it chains to) is the place
+to put them, because that's the only place Kermit looks for them
+automatically each time you start it.
+.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 the remote computer and your keyboard and screen. The remote Kermit is
+the file-transfer 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, RLOGIN, 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-level 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-transfer 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-related 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-keystroke 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-transfer 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-transfer state
+In this state, Kermit is exchanging file-transfer 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-transfer
+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-packet" and then press the Return or Enter key; this forces a
+fatal Kermit protocol error.
+.TP
+Remote Server state
+This is like Remote File-transfer 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-Server state, but in local mode, and therefore with its
+file-transfer display showing, and listening for single-key commands,
+as in Local File-transfer state. Usually this state is entered
+automatically when a remote Kermit program gives a GET command.
+.sp
+C-Kermit, Kermit 95, and MS-DOS Kermit all can switch automatically from
+Connect state to Local File-transfer 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-Kermit 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-Kermit. Kermit
+95 and MS-DOS Kermit, on the other hand, are true terminal emulators. Why
+is C-Kermit 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-line
+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-Kermit 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-in, but
+handled by running your external SSH client through a pseudoterminal.
+Using C-Kermit to control the SSH client gives you all of Kermit's
+features (file transfer, character-set 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-through) 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-high-speed", which should work for most modern AT-command-set
+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-server 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-port 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-modem 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-connected
+  set speed 57600       ; Or other desired speed
+  set flow rts/cts      ; If RTS and CTS are cross-connected
+  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-bit 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-Kermit 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-line 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-Kermit-Project Kermit
+protocol implementations really ARE slow. The best file-transfer partners
+for C-Kermit are: another copy of C-Kermit (7.0 or later) and Kermit 95.
+These combinations work well and they work fast by default. MS-DOS 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-Kermit and K95 also switch 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-to-date
+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.
+.TP
+Downloading Files
+Let's say you have Kermit 95, C-Kermit, or MS-DOS Kermit on your
+desktop computer, with a connection to a Unix computer that has
+C-Kermit 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 oofa.txt
+.sp
+(where oofa.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 oofa.txt oofa.zip oofa.html oofa.tar.gz
+.sp
+and/or you can use wildcards to send groups of files:
+.sp
+  kermit -s oofa.*
+.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-connecting, text/binary mode
+switching. Almost too easy, right?
+.TP
+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 oofa.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 have use shell quoting
+rules, since these aren't local files:
+.sp
+.nf
+  kermit -g "oofa.txt oofa.zip oofa.html oofa.tar.gz"
+  kermit -g "oofa.*"
+.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
+.TP
+Kermit Transfers the Old-Fashioned 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-Kermit 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.
+.TP
+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-transfer settings. This has been the default since
+C-Kermit 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-Kermit'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-bit connection.
+.RE
+.sp
+Obviously the success and performance of a file transfer also depends
+on C-Kermit's file transfer partner. Up-to-date, 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-Kermit, or
+send email to kermit-support@columbia.edu.
+.TP
+Advanced Kermit File-Transfer 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-file text/binary mode switching:
+SET TRANSFER MODE { AUTOMATIC, MANUAL } (HELP SET TRANSFER).
+.TP
+Cross-platform 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-set 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
+.TP
+Non-Kermit File Transfer
+You can also use C-Kermit 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-IN 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
+Pending publication of the next edition of the manual, the Kermit FTP
+client is thoroughly documented at the Kermit Project website:
+.sp
+  http://www.columbia.edu/kermit/ftpclient.html
+.sp
+You also can use HELP FTP and HELP SET FTP to get descriptions of Kermit's
+FTP-related 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-Kermit 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-Kermit can be an Internet
+Kermit Server, or it can be a client of an IKSD. You can make connections
+from C-Kermit 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
+  http://www.columbia.edu/kermit/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
+  http://www.columbia.edu/kermit/iksd.html
+.SH SECURITY
+All of C-Kermit's built-in TCP/IP networking methods (Telnet, Rlogin, IKSD,
+FTP, and HTTP) can be secured by one or more of the following IETF-approved
+methods:
+.PP
+\(bu	MIT Kerberos IV
+.br
+\(bu	MIT Kerberos V
+.br
+\(bu	SSL/TLS
+.br
+\(bu	Stanford SRP
+.PP
+For complete instructions see:
+.PP
+  http://www.columbia.edu/kermit/security.html
+.PP
+And as noted previously, you can also make SSH connections with C-Kermit if
+you already have an SSH client installed.
+.SH ALTERNATIVE COMMAND-LINE PERSONALITIES
+When invoked as "kermit" or any other name besides "ftp" or "telnet",
+C-Kermit has the command-line options described above in the OPTIONS
+section. However, if you invoke C-Kermit as "telnet" or "ftp", it changes
+its command-line personality to match. This can be done (among other ways)
+with symbolic links (symlinks). For example, if you want C-Kermit 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-line 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-personality command-line
+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-line 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-line 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/oofa.zip
+Downloads a file
+.TP
+kermit kermit://kermit.columbia.edu/kermit/f/READ.ME
+Ditto for IKSD
+.TP
+kermit iksd://kermit.columbia.edu/kermit/f/READ.ME
+(This works too)
+.TP
+kermit http://www.columbia.edu/kermit/index.html
+Grabs a web page
+.fi
+.SH LICENSE
+C-Kermit has an unusual license, but a fair and sensible one since the
+Kermit Project must support itself out of revenue: it's not a BSD license,
+not GPL, not Artistic, not commercial, not shareware, not freeware. It can
+be summed up like this: if you want C-Kermit for your own use, you can
+download and use it without cost or license (but we'd appreciate it if you
+would purchase the manual). But if you want to sell C-Kermit or bundle it
+with a product or otherwise distribute it in a commercial setting EXCEPT
+WITH AN OPEN-SOURCE OPERATING SYSTEM DISTRIBUTION such as Linux, FreeBSD,
+NetBSD, or OpenBSD, you must license it. To see the complete license, give
+the LICENSE command at the prompt, or see the COPYING.TXT file distributed
+with C-Kermit 7.0 or later, or download it from
+.sp
+  ftp://kermit.columbia.edu/kermit/c-kermit/COPYING.TXT
+.sp
+Send licensing inquiries to kermit@columbia.edu.
+.SH BUGS
+See the following files for listings of known bugs, limitations,
+workarounds, hints and tips:
+.TP
+ckcbwr.txt
+General C-Kermit bugs, hints, tips.
+.TP
+ckubwr.txt
+Unix-specific C-Kermit bugs, hints, tips.
+.PP
+Report bugs and problems by email to:
+.sp
+   kermit-support@columbia.edu.
+.sp
+Before requesting technical support, please read the hints here:
+.sp
+  http://www.columbia.edu/kermit/support.html
+.sp
+and also read the C-Kermit Frequently Asked Questions:
+.sp
+  http://www.columbia.edu/kermit/ckfaq.html
+.SH OTHER TOPICS
+There's way more to C-Kermit than we've touched on here -- 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-to-date information on documentation (or
+updated documentation itself) visit the Kermit Project website:
+.sp
+  http://www.columbia.edu/kermit/
+.PP
+There you will also find Kermit software packages for other platforms:
+different Unix varieties, Windows, DOS, VMS, IBM mainframes, and many
+others: 20+ years' worth.
+.SH DOCUMENTATION AND UPDATES
+The manual for C-Kermit is:
+.TP
+.I
+Using C-Kermit
+Frank da Cruz and Christine M. Gianone,
+Second Edition, Digital Press / Butterworth-Heinemann, Woburn, MA, 1997, 622
+pages, ISBN 1-55558-164-1. This is a printed book. It covers C-Kermit 6.0.
+.TP
+The C-Kermit 7.0 Supplement
+http://www.columbia.edu/kermit/ckermit2.html
+.TP
+The C-Kermit 8.0 Supplement
+http://www.columbia.edu/kermit/ckermit3.html
+.PP
+Visit C-Kermit home page:
+.sp
+  http://www.columbia.edu/kermit/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
+http://www.columbia.edu/kermit/scriptlib.html
+The Kermit script library and tutorial
+.TP
+http://www.columbia.edu/kermit/newfaq.html
+The Kermit FAQ (Frequently Asked Questions about Kermit)
+.TP
+http://www.columbia.edu/kermit/ckfaq.html
+The C-Kermit FAQ (Frequently Asked Questions about C-Kermit)
+.TP
+http://www.columbia.edu/kermit/telnet.html
+C-Kermit Telnet client documentation
+.TP
+http://www.columbia.edu/kermit/security.html
+C-Kermit security documentation (Kerberos, SSL/TLS, etc)
+.TP
+http://www.columbia.edu/kermit/cuiksd.html
+Internet Kermit Service user documentation
+.TP
+http://www.columbia.edu/kermit/iksd.html
+Internet Kermit Service administrator documentation
+.TP
+http://www.columbia.edu/kermit/studies.html
+Case studies.
+.TP
+http://www.columbia.edu/kermit/support.html
+Technical support.
+.TP
+http://www.columbia.edu/kermit/k95tutorial.html
+Kermit 95 tutorial.
+.TP
+comp.protocols.kermit.misc
+The Kermit newsgroup (unmoderated).
+.SH FILES
+.TP
+COPYING.TXT
+C-Kermit license.
+.TP
+~/.kermrc
+Initialization file.
+.TP
+~/.mykermrc
+Customization file.
+.TP
+~/.kdd
+Kermit dialing directory (see manual).
+.TP
+~/.knd
+Kermit network directory (see manual).
+.TP
+~/.ksd
+Kermit services directory (see manual).
+.TP
+ca_certs.pem
+Certificate Authority certifcates used for SSL connections.
+.TP
+ckuins.txt
+Installation instructions for Unix.  Also at
+http://www.columbia.edu/kermit/ckuins.html.
+.TP
+ckcbwr.txt
+General C-Kermit bugs, hints, tips.
+.TP
+ckubwr.txt
+Unix-specific C-Kermit bugs, hints, tips.
+.TP
+ckcplm.txt
+C-Kermit program logic manual.
+.TP
+ckccfg.txt
+C-Kermit compile-time configuration options.
+.TP
+ssh
+(in your PATH) SSH connection helper.
+.TP
+rz, sz, etc.
+(in your PATH) external protocols for XYZmodem.
+.TP
+/var/spool/locks (or whatever)
+UUCP lockfile for dialing out (see installation instructions).
+.SH AUTHORS
+.TP
+Software
+Frank da Cruz and Jeffrey E Altman,
+.br
+1985-present, with contributions from hundreds of others all over the
+world.
+.TP
+Documentation
+Frank da Cruz and Christine M Gianone
+.TP
+Address
+.nf
+The Kermit Project - Columbia Univerity
+612 West 115th Street
+New York NY 10025-7799
+USA
+.fi
+.TP
+E-Mail
+kermit@columbia.edu
+.TP
+Web
+http://www.columbia.edu/kermit/
+.fi
+.br
diff --git a/ckermit-8.0.211/ckupty.c b/ckermit-8.0.211/ckupty.c
new file mode 100644
index 0000000..705914c
--- /dev/null
+++ b/ckermit-8.0.211/ckupty.c
@@ -0,0 +1,1722 @@
+/*  C K U P T Y  --  C-Kermit pseudoterminal control functions for UNIX  */
+
+/*
+  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 <jaltman@secure-endpoints.com>
+  Secure Endpoints Inc., New York City
+  November 1999
+*/
+
+/*
+  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
+   . NeXTSTEP 3.x
+   . 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
+
+  Included but not tested yet in:
+   . Macintosh OSX, OpenBSD, and any other BSD44-based system not listed above
+
+  Failures include:
+   . SCO UNIX 3.2v4.2 (compile fails with syntax error in <memory.h>)
+   . HP-UX 8.00 and earlier (no vhangup or ptsname routines)
+*/
+
+#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.014, 20 Aug 2002";
+
+/* These will no doubt need adjustment... */
+
+#ifndef NEXT
+#define HAVE_SETSID
+#endif /* NEXT */
+#define HAVE_KILLPG
+#define HAVE_TTYNAME
+#define HAVE_WAITPID
+
+#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 <fcntl.h>
+#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 <utmpx.h> */
+#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 <sys/wait.h>
+#endif /* CK_WAIT_H */
+
+#ifdef STREAMSPTY
+#ifndef INIT_SPTY
+#define INIT_SPTY
+#endif /* INIT_SPTY */
+
+#include <sys/stream.h>
+#include <stropts.h>
+#include <termio.h>
+
+/* 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 <sys/ptyvar.h>
+
+#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 <tty.h>
+#endif /* HAVE_TTY_H */
+/*
+  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)<<IBSHIFT)
+#define cfgetispeed(tp) (((tp)->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 */
+
+extern int ttyfd;                       /* Standard Kermit usage */
+static int msg = 0;
+
+/* 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
+init_termbuf() {
+    int rc = 0;
+    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
+copy_termbuf(cp, len) char *cp; int len; {
+    if (len > sizeof(termbuf))
+      len = sizeof(termbuf);
+    memcpy((char *)&termbuf, cp, len);
+    termbuf2 = termbuf;
+}
+#endif /* TIOCPKT_IOCTL */
+
+VOID
+set_termbuf() {				/* Only make the necessary changes. */
+#ifndef	USE_TERMIO
+    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 */
+    if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) {
+	int x;
+	errno = 0;
+#ifdef INIT_SPTY
+	x = tcsetattr(spty, TCSANOW, &termbuf);
+	debug(F111,"set_termbuf tcsetattr(spty)",ckitoa(x),errno);
+#else
+	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
+#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 TIOCSTTY 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
+pty_cleanup(slave, pid, update_utmp) char *slave; int pid; int update_utmp; {
+#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)))
+	      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
+pty_getpty(fd, slave, slavelength) int slavelength; int *fd; char *slave; {
+    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;
+
+    debug(F100,"HAVE_OPENPTY","",0);
+    if (openpty(fd,
+		&slavefd,
+		slave,
+		(struct termios *)0,
+		(struct winsize *)0
+		)
+	)
+      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:
+    if (*fd >= 0) {
+#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
+	/* XXX 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];
+		*fd = open(slavebuf, O_RDWR|O_NDELAY);
+		if (*fd < 0)
+		  continue;
+                debug(F110,"pty_getpty() found pty master",slavebuf,0);
+		slavebuf[sizeof("/dev/") - 1] = 't'; /* got pty */
+		if (strlen(slavebuf) > slavelength -1) {
+		    close(*fd);
+		    *fd = -1;
+		    return(PTY_GETPTY_SLAVE_TOOLONG);
+		}
+                debug(F110,"pty_getpty() slavebuf [2]",slavebuf,0);
+		ckstrncpy(slave, slavebuf, slavelength);
+		return(0);
+	    }
+	}
+	return(PTY_GETPTY_NOPTY);
+    }
+#endif /*HAVE__GETPTY*/
+#endif /* HAVE_OPENPTY */
+}
+
+long
+pty_init() {
+#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
+pty_initialize_slave (fd) int fd; {
+#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 TIOCSTTY 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
+pty_open_ctty(slave, fd) char * slave; int *fd; {
+    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);
+#endif /* MUST_SETPGRP */
+
+    errno = 0;
+    *fd = open(slave, O_RDWR);
+    if (*fd < 0) {
+	debug(F111,"pty_open_ctty() open failure", slave, errno);
+	return(PTY_OPEN_SLAVE_OPENFAIL);
+    }
+#ifdef DEBUG
+    else if (deblog) {
+	debug(F110, "pty_open_ctty() open ok", slave, 0);
+    }
+#endif /* DEBUG */
+
+#ifdef MUST_SETPGRP
+    setpgrp(0, getpid());
+#endif /* MUST_SETPGRP */
+
+#ifdef TIOCSCTTY
+    errno = 0;
+    retval = ioctl(*fd, TIOCSCTTY, 0); /* Don't check return.*/
+    debug(F111,"pty_open_ctty() ioctl TIOCSCTTY",ckitoa(retval),errno);
+#endif /* TIOCSTTY */
+    return(0L);
+}
+
+long
+pty_open_slave(slave, fd) char *slave; int *fd; {
+    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)) != 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);
+    if (retval != 0) {
+        debug(F111,"pty_open_slave()","pty_open_ctty() failed",retval);
+	return(PTY_OPEN_SLAVE_OPENFAIL);
+    }
+    retval = pty_initialize_slave(*fd);
+    if (retval) {
+        debug(F111,"pty_open_slave()","pty_initialize_slave() failed",retval);
+        return(retval);
+    }
+#ifndef NO_DEVTTY
+    errno = 0;
+    testfd = open("/dev/tty", O_RDWR|O_NDELAY);
+    if (testfd < 0) {
+        debug(F111,"pty_open_slave() open failed","/dev/tty",errno);
+	close(*fd);
+	*fd = -1;
+	return(PTY_OPEN_SLAVE_NOCTTY);
+    }
+    close(testfd);
+#endif /* NO_DEVTTY */
+    debug(F110,"pty_open_slave()","success",0);
+    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 */
+
+static char Xline[17] = { 0, 0 };
+int pty_fork_pid = -1;
+
+/*
+  getptyslave()
+  Open the slave side of the pty, and do any initialization that is necessary.
+  The return value is a file descriptor for the slave side.
+*/
+int
+getptyslave() {
+    int t = -1;
+    long retval;
+#ifdef TIOCGWINSZ
+    struct winsize ws;
+    extern int cmd_rows, cmd_cols;
+#endif /* TIOCGWINSZ */
+
+    debug(F100,"getptyslave()","",0);
+
+    /*
+     * 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)) != 0) {
+	perror(Xline);
+	msg++;
+        debug(F111,"getptyslave()","Unable to open slave",retval);
+        return(-1);
+    }
+
+    debug(F111,"getptyslave","ttyfd",ttyfd);
+    debug(F111,"getptyslave","t",t);
+#ifdef INIT_SPTY
+    spty = t;
+#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. */
+    init_termbuf();
+#ifdef TIOCGWINSZ
+    if (cmd_rows || cmd_cols) {
+        memset((char *)&ws, 0, sizeof(ws));
+        ws.ws_col = cmd_cols;
+        ws.ws_row = cmd_rows;
+        ioctl(t, TIOCSWINSZ, (char *)&ws);
+    }
+#endif /* TIOCGWINSZ */
+
+    /* 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_termbuf();  /* Set the tty modes, and make this our controlling tty. */
+
+    if (t != 0)
+      dup2(t, 0);
+    if (t != 1)
+      dup2(t, 1);
+    if (t != 2)
+      dup2(t, 2);
+    if (t > 2)
+      close(t);
+
+    if (ttyfd > 2) {
+	close(ttyfd);
+        ttyfd = -1;
+    }
+    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
+exec_cmd(s) char * s; {
+    struct stringarray * q;
+    char ** args = NULL;
+
+    if (!s) return;
+    if (!*s) return;
+
+    q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
+    if (!q) return;
+
+    args = q->a_head + 1;
+    execvp(args[0],args);
+}
+
+/* Get a pty, scan input lines. */
+
+int
+do_pty(cmd) char * cmd; {
+    long retval;
+    int syncpipe[2];
+    int i;
+#ifdef HAVE_PTYTRAP
+    int x;
+#endif /* HAVE_PTYTRAP */
+
+    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);
+        return(-1);
+    }
+    debug(F110,"do_pty() Xline",Xline,0);
+
+#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 */
+	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 {
+        debug(F110,"do_pty()","Slave starts",0);
+        if (getptyslave() == 0) {
+#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);
+            write(syncpipe[1],"y",1);
+            close(syncpipe[0]);
+            close(syncpipe[1]);
+
+            exec_cmd(cmd);
+            debug(F111,"do_pty()","exec_cmd() returns - why?",errno);
+        }
+        debug(F110,"do_pty()","getptyslave() fails - exiting",0);
+        exit(1);
+    }
+    return(0);
+} /* end of do_pty() */
+
+
+VOID
+end_pty() {
+    msg = 0;				/* Message counter */
+    if (Xline[0] && pty_fork_pid >= 0) {
+        pty_cleanup(Xline,pty_fork_pid,1);
+        Xline[0] = '\0';
+        pty_fork_pid = -1;
+    }
+}
+#endif /* NETPTY */
diff --git a/ckermit-8.0.211/ckupty.h b/ckermit-8.0.211/ckupty.h
new file mode 100644
index 0000000..6749bec
--- /dev/null
+++ b/ckermit-8.0.211/ckupty.h
@@ -0,0 +1,174 @@
+/* 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 <jaltman@secure-endpoints.com>
+    Secure Endpoints Inc., New York City
+  November 1999
+*/
+#ifndef __PTY_INT_H__
+#include <sys/types.h>
+
+/* #define WANT_UTMP */
+/* We don't want all the utmp/wtmp stuff */
+
+#ifdef WANT_UTMP
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#endif /* HAVE_UTMP_H */
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif /* HAVE_UTMPX_H */
+#endif /* WANT_UTMP */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef __SCO__
+#include <sys/unistd.h>
+#endif /* __SCO__ */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <pwd.h>
+
+#ifdef HAVE_SYS_LABEL_H
+/* only SunOS 4? */
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif /* HAVE_SYS_LABEL_H */
+
+#include <signal.h>
+
+#ifdef HPUX
+#include <sys/ptyio.h>
+#endif /* HPUX */
+#ifdef sysvimp
+#include <compat.h>
+#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 <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#endif /* NO_SYS_SELECT_H */
+#endif /* COMMENT */
+
+#ifdef HAVE_STREAMS
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#endif /* HAVE_STREAMS */
+
+#ifdef POSIX_TERMIOS
+#ifndef ultrix
+#include <termios.h>
+#else
+#include <sgtty.h>
+#endif /* ultrix */
+#else /* POSIX_TERMIOS */
+#include <sgtty.h>
+#endif /* POSIX_TERMIOS */
+
+#include <netdb.h>
+/* #include <syslog.h> */
+#ifndef ultrix
+#include <string.h>
+#endif /* ultrix */
+/* #include <sys/param.h> */		/* (now done in ckcdeb.h) */
+
+#ifdef HAVE_STREAMS
+/* krlogin doesn't test sys/tty... */
+#ifdef HAVE_SYS_TTY_H
+#include <sys/tty.h>
+#endif /* HAVE_SYS_TTY_H */
+
+#ifdef HAVE_SYS_PTYVAR_H
+/* Solaris actually uses packet mode, so the real macros are needed too */
+#include <sys/ptyvar.h>
+#endif /* HAVE_SYS_PTYVAR_H */
+#endif /* HAVE_STREAMS */
+
+#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 *));
+_PROTOTYP(long pty_open_ctty, (char *, 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__ */
diff --git a/ckermit-8.0.211/ckuscr.c b/ckermit-8.0.211/ckuscr.c
new file mode 100644
index 0000000..98d2fd6
--- /dev/null
+++ b/ckermit-8.0.211/ckuscr.c
@@ -0,0 +1,688 @@
+#include "ckcsym.h"
+
+#ifndef NOICP
+#ifndef NOSCRIPT
+char *loginv = "Script Command, 8.0.032, 20 Dec 2001";
+
+/*  C K U S C R  --  expect-send script implementation  */
+
+/*
+  Copyright (C) 1985, 2004,
+    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, Columbia University,
+  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 "ckcdeb.h"
+#include <signal.h>
+#ifdef NT
+#include <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckuusr.h"
+#include "ckcnet.h"
+#include "ckcsig.h"
+
+_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 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++] = 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("<EOT>");
+	if (seslog && duplex)
+            logstr("<EOT>",5);
+    } else if (!strcmp(seq_buf,"BREAK") ||
+	       !strcmp(seq_buf,"\\b") ||
+	       !strcmp(seq_buf,"\\B")) {
+	ttsndb();
+	if (scr_echo) conol("<BREAK>");
+	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(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(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
+dologin(cmdstr) char *cmdstr; {
+
+#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 */
diff --git a/ckermit-8.0.211/ckusig.c b/ckermit-8.0.211/ckusig.c
new file mode 100644
index 0000000..9f60b96
--- /dev/null
+++ b/ckermit-8.0.211/ckusig.c
@@ -0,0 +1,352 @@
+/* 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, 2004,
+    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 <signal.h>
+#ifdef NT
+#include <setjmpex.h>
+#include <excpt.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include "ckcsig.h"
+
+#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);
+}
diff --git a/ckermit-8.0.211/ckusig.h b/ckermit-8.0.211/ckusig.h
new file mode 100644
index 0000000..bf61e38
--- /dev/null
+++ b/ckermit-8.0.211/ckusig.h
@@ -0,0 +1,79 @@
+/*  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, 2004,
+    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 */
+
diff --git a/ckermit-8.0.211/ckutio.c b/ckermit-8.0.211/ckutio.c
new file mode 100644
index 0000000..4c517cc
--- /dev/null
+++ b/ckermit-8.0.211/ckutio.c
@@ -0,0 +1,14492 @@
+#ifdef aegis
+char *ckxv = "Aegis Communications support, 8.0.303, 17 Apr 2004";
+#else
+#ifdef Plan9
+char *ckxv = "Plan 9 Communications support, 8.0.303, 17 Apr 2004";
+#else
+char *ckxv = "UNIX Communications support, 8.0.303, 17 Apr 2004";
+#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),
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 */
+
+/* Includes */
+
+#include "ckcsym.h"			/* This must go first   */
+#include "ckcdeb.h"			/* This must go second  */
+
+#ifdef OSF13
+#ifdef CK_ANSIC
+#ifdef _NO_PROTO
+#undef _NO_PROTO
+#endif /* _NO_PROTO */
+#endif /* CK_ANSIC */
+#endif /* OSF13 */
+
+#include <errno.h>			/* System error numbers */
+
+#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 <sys/time.h>
+#include <select.h>
+#define FD_SETSIZE (3 * sizeof(long) * 8)
+static struct timeval tv;
+#endif /* Plan9 */
+
+#ifdef CLIX
+#include <sys/time.h>
+#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 <sys/ndir.h>
+#else /* !XNDIR */
+#ifdef NDIR
+#include <ndir.h>
+#else /* !NDIR, !XNDIR */
+#ifdef RTU
+#include "/usr/lib/ndir.h"
+#else /* !RTU, !NDIR, !XNDIR */
+#ifdef DIRENT
+#ifdef SDIRENT
+#include <sys/dirent.h>
+#else
+#include <dirent.h>
+#endif /* SDIRENT */
+#else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
+#include <sys/dir.h>
+#endif /* DIRENT */
+#endif /* RTU */
+#endif /* NDIR */
+#endif /* XNDIR */
+
+#ifdef QNX
+#include <sys/dev.h>
+#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 <sys/poll.h>, 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 <poll.h>		/* "standard" (SVID) i/o multiplexing, etc */
+#else /* AIXRS */
+#ifdef SVR4			/* AIX 3.2 is like SVID... */
+#include <poll.h>
+#else				/* But AIX 3.1 is not ... */
+#include <sys/poll.h>		/* 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 <signal.h>                     /* Signals */
+
+/* For setjmp and longjmp */
+
+#ifndef ZILOG
+#include <setjmp.h>
+#else
+#include <setret.h>
+#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 */
+/*
+  Minix 2.0 support added by Terry McConnell,
+  Syracuse University <tmc@barnyard.syr.edu>
+  No more sgtty interface, posix compliant.
+*/
+#ifdef MINIX2
+#define _MINIX   /* Needed for some Minix header files */
+#undef MINIX     /* Old minix 1.0: used sgtty interface */
+#define BSD44ORPOSIX
+#define SVORPOSIX
+#define DCLTIMEVAL
+#define NOFILEH
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <limits.h>
+#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 <hedrick@aramis.rutgers.edu>.
+ MINIX also has V7 enabled.
+*/
+#ifdef MINIX
+#define TANDEM 0
+#define MYREAD
+#define NOSYSIOCTLH
+#include <limits.h>
+#endif /* MINIX */
+
+#ifdef CK_REDIR		/* <sys/wait.h> 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 <sys/wait.h>			/* 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 <sys/utsname.h>
+
+#ifdef TRU64				/* Tru64 UNIX 4.0 and later */
+/* Verified on Tru64 4.0F - might break on 4.0E or earlier */
+#include <sys/sysinfo.h>		/* (don't know about OSF/1 or DU) */
+#include <machine/hal_sysinfo.h>
+#endif /* TRU64 */
+
+#ifdef SOLARIS25			/* Solaris 2.5 and later */
+#include <sys/systeminfo.h>		/* (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 <stat.h>			/* For chasing symlinks, etc. */
+#else
+#include <sys/stat.h>
+#endif /* CIE */
+
+/* UUCP lockfile material... */
+
+#ifndef NOUUCP
+#ifdef USETTYLOCK
+#ifdef HAVE_BAUDBOY			/* Red Hat baudboy/lockdev */
+#include <baudboy.h>
+#else
+#ifdef USE_UU_LOCK
+#ifdef __FreeBSD__
+#include <libutil.h>			/* FreeBSD */
+#else
+#include <util.h>			/* OpenBSD */
+#endif /* HAVE_BAUDBOY */
+#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 <sys/file.h> */
+
+#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 <sys/file.h>
+#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 <termios.h>
+#ifdef LINUX
+#include <sys/ioctl.h>
+#endif /* LINUX */
+#ifdef QNX16
+#include <ioctl.h>
+#else
+#ifdef QNX6
+#include <ioctl.h>
+#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 <termio.h>
+#endif /* POSIX */
+#endif /* BSD44 */
+#ifdef TERMIOX
+/* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
+#include <termiox.h>
+  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 <sys/termiox.h>
+  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 <termio.h>
+#endif /* COHERENT */
+
+#ifdef MINIX				/* MINIX uses ioctl's */
+#define NOSYSIOCTLH			/* but has no <sys/ioctl.h> */
+#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 <sys/ioctl.h>
+#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 <sys/filio.h>			/* 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 <sys/filio.h>
+#else
+#ifdef SOLARIS
+#include <sys/filio.h>
+#endif /* SOLARIS */
+#endif /* UNIXWARE */
+#endif /* FIONREAD */
+
+#ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
+/*
+  <sys/socket.h> 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 */
+#ifdef FIONREAD
+#undef FIONREAD
+#endif /* FIONREAD */
+#endif /* XENIX */
+
+/* Whether to include <fcntl.h> */
+
+#ifndef is68k				/* Only a few don't have this one. */
+#ifndef BSD41
+#ifndef FT21
+#ifndef FT18
+#ifndef COHERENT
+#include <fcntl.h>
+#endif /* COHERENT */
+#endif /* FT18 */
+#endif /* FT21 */
+#endif /* BSD41 */
+#endif /* not is68k */
+
+#ifdef COHERENT
+#ifdef _I386
+#include <fcntl.h>
+#else
+#include <sys/fcntl.h>
+#endif /* _I386 */
+#endif /* COHERENT */
+
+#ifdef ATT7300				/* Unix PC, internal modem dialer */
+#include <sys/phone.h>
+#endif /* ATT7300 */
+
+#ifdef HPUX				/* HP-UX variations. */
+#define HPUXJOBCTL
+#include <sys/modem.h>			/* HP-UX modem signals */
+#ifdef hp9000s500			/* Model 500 */
+#undef HPUXJOBCTL
+#endif /* hp9000s500 */
+#ifdef HPUXPRE65
+#undef HPUXJOBCTL
+typedef long mflag;
+#endif /* HPUXPRE65 */
+#ifdef HPUXJOBCTL
+#include <sys/bsdtty.h>			/* 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 <time.h>
+#endif /* TIMEH */
+#endif /* NOTIMEH */
+
+#ifndef NOSYSTIMEH
+#ifdef SYSTIMEH
+#include <sys/time.h>
+#endif /* SYSTIMEH */
+#endif /* NOSYSTIMEH */
+
+#ifndef NOSYSTIMEBH
+#ifdef SYSTIMEBH
+#include <sys/timeb.h>
+#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 <linux/serial.h>
+#endif /* OLINUXHISPEED */
+#ifdef __alpha__			/* Linux on DEC Alpha */
+#ifndef __GLIBC__			/* But not with glibc */
+#include <asm/termios.h>
+#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 <sys/types.h> but some systems get them from
+  <sys/select.h>...  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 <sys/select.h>
+#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 <default_acl.h>
+#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 <file.h>... */
+
+#ifndef FREAD
+#define FREAD 0x01
+#endif /* FREAD */
+
+#ifndef FWRITE
+#define FWRITE 0x10
+#endif /* FWRITE */
+
+#ifndef O_RDONLY
+#define O_RDONLY 000
+#endif /* O_RDONLY */
+
+#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 */
+
+#ifdef __GNUC__
+#ifdef XENIX
+/*
+  Because Xenix <time.h> 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 */
+
+/* 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 */
+
+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 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 <stdio.h> */
+_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 <sys/time.h>
+#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 <sys/asyc.h>			/* 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( 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 <kernel/OS.h>
+/* #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
+timerh(foo) int foo; {
+    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
+xtimerh(foo) int foo; {			/* Like timerh() but does */
+#ifdef BEOSORBEBOX			/* not reset the timer itslef */
+/* #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
+cctrap(foo) int foo; {			/* Needs arg for ANSI C */
+  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";
+    hexdump(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";
+    hexdump(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 <sys/stream.h>			/* typedef mblk_t needed by ptem.h */
+#include <sys/ptem.h>			/* for ttgwsiz() */
+#endif /* XENIX */
+
+#ifdef I386IX				/* Ditto for Interactive */
+#include <sys/stream.h>
+#include <sys/ptem.h>
+#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 */
+}
+
+
+#ifndef NOSIGWINCH
+#ifdef SIGWINCH
+SIGTYP
+winchh(foo) int foo; {			/* SIGWINCH handler */
+    int x = 0;
+#ifdef NETPTY
+    extern int pty_fork_pid;
+#endif /* NETPTY */
+#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
+sighup(foo) int foo; {			/* SIGHUP handler */
+    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 */
+
+#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
+    if (!cttnam[0])
+      ctermid(cttnam);
+#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
+   -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
+ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
+
+#ifdef BSD44
+#define ctermid(x) strcpy(x,"")
+#else
+#ifdef SVORPOSIX
+#ifndef CIE
+    extern char *ctermid();		/* Wish they all had this! */
+#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... */
+
+#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...
+*/
+    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 */
+ 	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(ttname);
+		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]);
+		    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 */
+	    x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
+	    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,&ltchold) < 0) {
+	    debug(F100,"ttopen TIOCGLTC failed","",0);
+	} else {
+	    ltcharf = 1;		/* It worked. */
+	    ioctl(ttyfd,TIOCGLTC,&ltchnoi); /* 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
+do_open(ttname) char *ttname; {
+    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
+ttclos(foo) int foo; {			/* Arg req'd for signal() prototype */
+    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);
+
+    if (ttfdflg)			/* If we inherited ttyfd from */
+      return(0);			/* another process, don't close it. */
+
+    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
+    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
+    if (ttpty) {
+#ifndef NODOPTY
+        end_pty();
+#endif /* NODOPTY */
+        close(ttyfd);
+	netconn = 0;
+	wasclosed = 1;
+        ttpty = 0;
+        ttyfd = -1;
+        return(0);
+    }
+#endif /* NETPTY */
+
+#ifdef	NETCONN
+    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);
+	    }
+	}
+	/* 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,&ltchold) < 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
+ttchkpid(f) char *f; {
+    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
+ttrpid(name) char *name; {
+    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 <sys/mkdev.h>			/* look here */
+#else					/* or for SunOS versions */
+#ifdef SUNOS4				/* ... */
+#include <sys/sysmacros.h>		/* 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
+#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
+ttlock(ttdev) char *ttdev; {
+
+    int x, n;
+    int islink = 0;
+
+#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. */
+    if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
+      ckstrncpy(lockname,ttdev+5,DEVNAMLEN);
+    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... */
+    struct stat devbuf;			/* For device numbers (SVR4). */
+
+#ifdef PIDSTRING
+    char pid_str[32];			/* My pid in string format. */
+#endif /* PIDSTRING */
+
+    char *device, *devname;
+
+#define LFNAML 256			/* 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 */
+    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 = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
+	if (haslock) {			      /* If we got the lockfile */
+#ifdef RTAIX
+	    link(flfnam,lkflfn);
+#endif /* RTAIX */
+#ifdef CKSYMLINK
+#ifndef LFDEVNO
+	    if (islink && lock2[0])
+	      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;			/* <instance>p<port> 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 = <instance>p<port> */
+    while (*unit && !isdigit(*unit))	/* Search for digit... */
+      unit++;
+    p = unit;				/* Verify <num>p<num> 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 <termios.h>) 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
+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 */
+/* tthflow */ {
+
+    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 {			/* 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 */
+    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
+ttsetflow(flow) int flow; {
+    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 */
+
+    x = tcsetattr(ttyfd,TCSADRAIN,&tttvt);
+    debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x);
+    if (x < 0) {
+	debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno);
+	return(-1);
+    }
+#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
+ttsspd(cps) int cps; {
+    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  /* Not USETCSETSPEED */
+
+#ifdef MINIX2        /* Hack alert */
+#define MINIX        /* Use pre-2.0 speed selection for Minix 2.0 as well */
+#endif /* MINIX2 */
+
+    /* 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 <carlo@sg.tn.tudelft.nl>:
+  "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 B921600
+      case 92160: s = B921600; break;
+#endif /* B921600 */
+#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);
+	x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
+	debug(F101,"ttsspd tcsetattr","",x);
+	if (x < 0) return(-1);
+#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
+  apply to the system where C-Kermit was built, rather than to the one where
+  it is running.  Suggestions for improvement are always welcome.
+*/
+long *
+ttspdlist() {
+    int i;
+    for (i = 0; i < NSPDLIST; i++)	/* Initialize the list */
+      spdlist[i] = -1L;
+    i = 1;
+
+#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 */
+#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 */
+
+#ifdef MINIX2
+/* End of hack to make MINIX2 use MINIX1 speed setting */
+#undef MINIX
+#endif /* MINIX2 */
+
+#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 92160: ss = 921600L; break;
+#endif /* B921600 */
+      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.
+ *
+ * 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.
+ *
+ * myunrd() is currently not called from anywhere inside kermit...
+ */
+#ifdef COMMENT /* not used */
+myunrd(ch) CHAR ch; {
+    if (my_item >= 0) {
+	mybuf[my_item--] = ch;
+	++my_count;
+    }
+}
+#endif /* COMMENT */
+
+/*  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
+ttpushback(s,n) CHAR * s; int n; {
+    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 */
+    if (deblog) hexdump("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(F100,"SVORPOSIX myfillbuf calling read()","",0);
+#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;
+	  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) {
+        if ((n = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
+	  return(-3);
+        else
+	  return(n);
+    }
+#endif /* RLOGCODE */
+#endif /* KRB4 */
+#ifdef KRB5
+#ifdef RLOGCODE
+    if (ttnproto == NP_EK5LOGIN) {
+        if ((n = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
+	  return(-3);
+        else
+	  return(n);
+    }
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+    if (ttnproto == NP_K5U2U) {
+        if ((n = krb5_u2u_read(ttyfd,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) {
+        if (pty_trap_handler(ttyfd) > 0) {
+            ttclos(0);
+            return(-3);
+        }
+    }
+#endif /* HAVE_PTYTRAP */
+#endif /* NETPTY */
+    n = read(fd, mybuf, sizeof(mybuf));
+    debug(F101,"SVORPOSIX myfillbuf","",n);
+    debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
+    debug(F101,"SVORPOSIX myfillbuf errno","",errno);
+    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)
+	  hexdump("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 */
+
+#ifdef MINIX2
+#undef MINIX
+#endif /* MINIX2 */
+
+/*  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
+tt_tnopt(n) int n; {			/* Handle Telnet options */
+    /* In case caller did not already check these conditions...  */
+    if (n == IAC &&
+	((xlocal && netconn && IS_TELNET()) ||
+	 (!xlocal && sstelnet))) {
+	extern int duplex;
+	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(&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 */
+	return(netflui());
+    }
+#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
+conbgt(flag) int flag; {
+    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 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 MINIX2
+#undef BSD44ORPOSIX
+#endif /* MINIX2 */
+
+/* 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 */
+
+#ifdef MINIX2
+#define BSD44ORPOSIX
+#endif /* MINIX2 */
+
+    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 */
+
+/* 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 <a.out.h>
+#include <sys/proc.h>
+#endif /* COHERENT */
+#endif /* MINIX2 */
+#endif /* MINIX */
+
+#ifdef COHERENT
+#include <l.out.h>
+#include <sys/proc.h>
+#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
+in_chk(channel, fd) int channel, fd; {
+    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 <sys/socket.h> 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
+ttxin(n,buf) int n; CHAR *buf; {
+    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
+ttol(s,n) int n; CHAR *s; {
+    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) hexdump("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
+        if (deblog) hexdump("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,s,n,0));
+            } else
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+            if (ttnproto == NP_K5U2U) {
+                return(krb5_u2u_write(ttyfd,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,&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 communication line, 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 characters that were input are copied into "dest" with their parity bits
+  stripped if parity was selected.  Returns the number of characters read.
+  Characters 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().
+
+  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.
+*/
+
+static int csave = -1;
+
+#ifndef NOXFER
+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 /* __SDTC__ */
+#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. */
+
+    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
+	    /* debug(F101,"ttinl i","",i); */
+	    errno = 0;
+	    if (csave > -1) {
+	        n = csave;
+		debug(F101,"ttinl unsaving","",n);
+	    } else
+#ifdef COMMENT
+	      if (xlocal && conchk() > 0) {
+		  /* Here we could catch keyboard interruptions. */
+		  /* But this would be VERY expensive. */
+		  /* We could also do it in myread() but it would be */
+		  /* expensive there too -- even if done with select()... */
+	      }
+#endif /* COMMENT */
+	      if ((n = myread()) < 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?) */
+
+	    if (csave > -1)		/* Char saved from last time */
+	      ch = csave;
+	    else if ((n = read(fd, &ch, 1)) < 1)
+	      break;			/* Error - break out of while loop */
+	    n = ch;
+
+#endif /* MYREAD */
+
+	    /* Get here with char in n */
+
+#ifdef CK_ENCRYPTION
+	    /* If csave > -1 we already decrypted this character */
+	    /* So don't decrypt it again */
+	    if (TELOPT_U(TELOPT_ENCRYPTION) && csave == -1) {
+		CHAR ch = n;
+		ck_tn_decrypt(&ch,1);
+		n = ch;
+	    }
+#endif /* CK_ENCRYPTION */
+
+	    csave = -1;			/* Unflag that we unsaved a char */
+
+#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
+	    if (flag == 0) {		/* Find the Start-Of-Packet. */
+		if ((n & sopmask) == start) { /* Got it */
+		    flag = 1;
+		} else {		/* Keep looking... */
+		    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...
+*/
+	    if (!havelen) {
+		if (i == 2) {
+		    pktlen = xunchar(dest[1] & 0x7f);
+		    if (pktlen > 1) {
+			havelen = 1;
+			debug(F101,"ttinl length","",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 (
+#ifdef PARSENSE
+/*
+  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) */
+#else /* !PARSENSE */
+/*
+  Built without PARSENSE, so just look for packet terminator.
+*/
+		((n & 0x7f) == eol)
+#endif /* PARSENSE */
+		) {
+#ifndef PARSENSE
+		debug(F101,"ttinl got eol","",eol); /* (or turn) */
+		dest[i] = '\0';		/* Yes, terminate the string, */
+		/* debug(F101,"ttinl i","",i); */
+#else
+#ifdef DEBUG
+		if (deblog) {
+		    if ((n & 0x7f) != eol) {
+			debug(F101,"ttinl EOP length","",pktlen);
+			debug(F101,"ttinl i","",i);
+#ifdef MYREAD
+#ifdef PARSENSE
+/*
+  We read a packet based on its length.  This leaves the EOP character still
+  unread, and so ttchk() will always return at least 1 because of this.  But
+  if we know it is there, we can safely get rid of it.  So...
+*/
+			{
+			    int x;
+			    while (my_count > 0) {
+				x = ttinc(0);
+				/* Start of next packet */
+				if (x == start) { /* Save for next time */
+				    csave = (unsigned)((unsigned)x & 0xff);
+				    debug(F000,"ttinl csaved","",x);
+				    break;
+				}
+				debug(F000,"ttinl removed","",x);
+			    }
+			}
+#endif /* PARSENSE */
+#endif /* MYREAD */
+
+		    } else debug(F101,"ttinl got eol","",eol); /* (or turn) */
+		}
+#endif /* DEBUG */
+		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 = ttprty;
+		    needpchk = 0;
+		}
+#endif /* PARSENSE */
+		if (timo) {		/* Turn off timer. */
+		    ttimoff();
+		}
+#ifdef COMMENT
+		debug(F011,"ttinl got", dest, (i < 60) ? i : -60);
+#else /* COMMENT */
+                hexdump("ttinl got",dest,i);
+#endif /* COMMENT */
+#ifdef STREAMING
+		/* ttinl() was called because there was non-packet */
+		/* data sitting int the 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
+ttinc(timo) int timo; {
+
+    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(&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. */
+#ifdef NETCONN
+	  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(&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);
+	    }
+	}
+#ifdef NETCONN
+	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
+ttwait(fd, secs) int fd, secs; {
+    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
+msleep(m) int m; {
+/*
+  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 <times.h> ? */
+#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
+ztime(s) char **s; {
+
+#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.
+*/
+    char *asctime();
+    struct tm *localtime();
+    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 <time.h>, 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.h> */
+    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 <time.h> */
+    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
+congetbuf(x) int x; {
+    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;
+    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 NONOSETBUF
+    if (x > -1) {
+	setbuf(stdout,NULL);    /* Make console unbuffered. */
+	debug(F100,"concb setbuf A","",0);
+    }
+#else
+#ifndef aegis
+#ifndef NOSETBUF
+    if (x > -1) {
+	setbuf(stdout,NULL);    /* Make console unbuffered. */
+	debug(F100,"concb setbuf B","",0);
+    }
+#endif /* NOSETBUF */
+#endif /* aegis */
+#endif /* NONOSETBUF */
+
+#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
+conxo(x,s) int x; char *s; {
+
+#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
+conol(s) char *s; {
+    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 = 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
+conola(s) char *s[]; {
+    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
+conoll(s) char *s; {
+    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(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
+coninc(timo) int timo; {
+    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(&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(&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 <sys/phone.h> 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
+ttscarr(carrier) int carrier; {
+    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 BSD44ORPOSIX
+carrctl(ttpar, carrier)	struct termios *ttpar; int carrier;
+#else /* ATTSV */
+carrctl(ttpar, carrier)	struct termio *ttpar; int carrier;
+#endif /* BSD44ORPOSIX */
+/* carrctl */ {
+    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 <sys/termio.h> 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 <sys/qioctl.h>
+
+    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 <sys/qioctl.h>:
+ *
+ * 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 <sys/modem.h> */
+#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 <sys/ioctl.h> or elsewhere.
+  If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
+  are needed.
+*/
+#ifndef TIOCMGET
+#include <sys/ttycom.h>
+#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
+psuspend(flag) int flag; {
+
+#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 COHERENT
+#ifndef NOGETID_PROTOS
+extern UID_T getuid(), geteuid(), getreuid();
+extern GID_T getgid(), getegid(), getregid();
+#endif /* NOGETID_PROTOS */
+#else
+extern UID_T getreuid();
+extern GID_T getregid();
+#endif /* COHERENT */
+#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 <ske@pkmab.se>
+
+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 <mike.long@analog.com>, 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
+priv_ini() {
+    int err = 0;
+
+#ifndef HAVE_BAUDBOY
+
+    /* 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_BAUDBOY */
+    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_BAUDBOY
+    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)
+	    switchgid(privgid,realgid);
+	  return(1);
+      }
+#endif /* HAVE_BAUDBOY */
+    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_BAUDBOY
+    if (privuid != (UID_T) -1)
+       if (switchuid(privuid,realuid))
+	  err |= 1;
+
+    if (privgid != (GID_T) -1)
+       if (switchgid(privgid,realgid))
+	err |= 2;
+#endif /* HAVE_BAUDBOY */
+    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_BAUDBOY
+#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_BAUDBOY */
+}
+
+/* P R I V _ O P N  --  For opening protected files or devices. */
+
+int
+priv_opn(name, modes) char *name; int modes; {
+    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); */
+    }
+}
+
+/* T T R U N C M D  --  Redirect an external command over the connection. */
+
+#ifdef CK_REDIR
+int
+ttruncmd(s) char *s; {
+    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);
+    }
+    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 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 <stdarg.h>
+#else /* CK_ANSIC */
+#include <varargs.h>
+#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. We fake one here using time(2) */
+
+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);
+}
+
+/* Minix does not support symbolic links. We implement a version of
+   readlink that always fails */
+
+int
+readlink(const char *path, void *buf, size_t bufsiz) {
+    errno = ENOSYS;
+    return(-1);
+}
+#endif /* MINIX2 */
diff --git a/ckermit-8.0.211/ckututor.txt b/ckermit-8.0.211/ckututor.txt
new file mode 100644
index 0000000..9448126
--- /dev/null
+++ b/ckermit-8.0.211/ckututor.txt
@@ -0,0 +1,1959 @@
+
+C-KERMIT 8.0 UNIX MANUAL PAGE AND TUTORIAL
+
+     Frank da Cruz, Christine M. Gianone
+     [1]The Kermit Project, [2]Columbia University
+     
+   [ [3]PDF version ] [ [4]Nroff version ]
+   
+     This document is intended to give the beginner sufficient
+     information to make basic (if not advanced) use of C-Kermit 8.0.
+     Although it might be rather long for a Unix manual page (about 1600
+     lines), it's still far shorter than the C-Kermit manual, which
+     should be consulted for advanced topics such as customization,
+     character-sets, scripting, etc. We also attempt to provide a clear
+     structural overview of C-Kermit'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 the new release. 
+     
+   Most recent update: 24 October 2002
+    ________________________________________________________________________
+  
+  CONTENTS
+     * [5]DESCRIPTION
+     * [6]SYNOPSIS
+     * [7]OPTIONS
+     * [8]COMMAND LANGUAGE
+     * [9]INITIALIZATION FILE
+     * [10]MODES OF OPERATION
+     * [11]MAKING CONNECTIONS
+     * [12]TRANSFERRING FILES WITH KERMIT
+     * [13]KERMIT CLIENT/SERVER CONNECTIONS
+     * [14]KERMIT'S BUILT-IN FTP AND HTTP CLIENTS
+     * [15]INTERNET KERMIT SERVICE
+     * [16]SECURITY
+     * [17]ALTERNATIVE COMMAND-LINE PERSONALITIES
+     * [18]LICENSE
+     * [19]OTHER TOPICS
+     * [20]DOCUMENTATION AND UPDATES
+     * [21]FILES
+     * [22]AUTHORS
+     _________________________________________________________________
+   
+   DESCRIPTION [ [23]Top ] [ [24]Contents ] [ [25]Next ]
+   
+   [26]C-Kermit is an all-purpose communications software package from
+   the [27]Kermit Project at [28]Columbia University that:
+   
+     * Is portable to many platforms, Unix and non-Unix alike.
+     * Can make both serial and network connections.
+     * Can conduct interactive terminal sessions over its connection.
+     * Can transfer text or binary files over the same connection.
+     * Can convert text-file character sets in terminal mode or file
+       transfer.
+     * Is customizable in every aspect of its operation.
+       
+   C-Kermit is a modem program, a Telnet client, an Rlogin 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-approved security methods including Kerberos IV, Kerberos V,
+   SSL/TLS, and SRP and it can also make SSH (Secure Shell) connections
+   through your external SSH client application. It can be the far-end
+   file-transfer 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 [[29]RFC2839, [30]RFC2840].
+   
+   And perhaps most important, everything you can do "by hand"
+   (interactively) with C-Kermit, can be "scripted" (automated) using its
+   built-in cross-platform transport-independent script programming
+   language, which happens to be identical to its interactive command
+   language.
+   
+   This manual page offers an overview of C-Kermit 8.0 for Unix ("Unix"
+   is an operating system family that includes AIX, DG/UX, FreeBSD,
+   HP-UX, 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-Kermit manual and supplements (see [31]DOCUMENTATION
+   below). For further information about C-Kermit, Kermit software for
+   other platforms, and Kermit manuals, visit the Kermit Project website:
+   
+  [32]http://www.columbia.edu/kermit/
+
+   This is a longer-than-average manual page, and yet it barely scratches
+   the surface. Don't be daunted. C-Kermit 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.
+   
+   [ [33]Kermit Home ] [ [34]C-Kermit Home ] [ [35]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  SYNOPSIS [ [36]Top ] [ [37]Contents ] [ [38]Next ] [ [39]Previous ]
+  
+   Usage:  kermit [filename] [-x arg [-x arg]...[-yyy]..] [ {=,--,+} text
+   ] ]
+   Or:    kermit URL
+   
+     * -x is an option requiring an argument;
+     * -y is an option with no argument.
+       
+   If the first command-line argument is the name of a file,
+   interactive-mode 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 \%1, \%2, ...
+   \%9. The "+" argument is like "=" but for use in "kerbang scripts"
+   (explained [40]below). A second command-line format allows the one and
+   only argument to be a [41]Telnet, FTP, HTTP, or IKSD URL.
+   
+   Order of execution:
+   
+    1. [42]The command file (if any).
+    2. [43]The initialization file, if any, unless suppressed with -Y.
+    3. [44]The customization file (if it is executed by the
+       initialization file).
+    4. [45]The command-line URL (if any, and if so, execution stops
+       here).
+    5. [46]Command-line options (if any).
+    6. [47]Interactive commands.
+       
+   Some command-line 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.
+   
+     Bear in mind that C-Kermit can be built with selected features
+     disabled, and also that certain features are not available on all
+     platforms. For example, C-Kermit 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-Kermit lacks a
+     feature mentioned here, use its SHOW FEATURES command to see what
+     might have been excluded. 
+     
+   C-Kermit has three kinds of commands: regular single-letter
+   command-line options, extended-format command-line options, and
+   interactive commands.
+   
+   [ [48]Kermit Home ] [ [49]C-Kermit Home ] [ [50]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  OPTIONS [ [51]Top ] [ [52]Contents ] [ [53]Next ] [ [54]Previous ]
+  
+   Like most Unix commands, C-Kermit can be be given options on the
+   command line. But C-Kermit also can be used interactively by giving it
+   [55]commands composed of words, which are more intuitive than cryptic
+   command-line options, and more flexible too. In other words, you don't
+   have to use C-Kermit's command-line options, but they are available if
+   you want to. (By the same token, you don't have to use its interactive
+   commands either -- you can use either or both in any combination.)
+   
+   C-Kermit 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-line options, put them after the word "kermit" but
+   before pressing Return or Enter, separated by spaces, for example:
+   
+  $ kermit -s ckermit.tar.gz
+
+   ('$' is the shell prompt; "kermit -s ckermit.tar.gz" is what you type,
+   followed by Return or Enter.)
+   
+   Here is a list of C-Kermit's single-letter command-line options, which
+   start with a single dash (-), in ASCII ("alphabetical") order.
+   Alphabetic case is significant (-A is not the same as -a). The Action?
+   column contains Y for action options and N for non-action options.
+   Option Action? Description
+   -0 N (digit zero) 100% transparent Connect state for "in-the-middle"
+   operation: 8 bits, no parity, no escape character, everything passes
+   through.
+   -8 N (digit eight) Connection is 8-bit clean (this is the default in
+   C-Kermit 8.0). Equivalent to the EIGHTBIT command, which in turn is a
+   shortcut for SET TERMINAL BYTESIZE 8, SET COMMAND BYTESIZE 8, SET
+   PARITY NONE.
+   -9 arg N (digit nine) Make a connection to an FTP server. Equivalent
+   to the FTP OPEN command.
+   Argument: IP-address-or-hostname[:optional-TCP-port].
+   NOTE: C-Kermit also has a separate FTP command-line personality, with
+   regular FTP-like command-line syntax. [56]More about this below.
+   -A N Kermit is to be started as an Internet service (IKSD) (only from
+   inetd.conf).
+   -B N 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.
+   -C arg N Interactive-mode Commands to be executed.
+   Argument: Commands separated by commas, list in doublequotes.
+   -D arg N Delay before starting to send in Remote mode. Equivalent to
+   the SET DELAY command.
+   Argument: Number of seconds.
+   -E N Exit automatically when connection closes. Equivalent to SET EXIT
+   ON-DISCONNECT ON.
+   -F arg N Use an open TCP connection.
+   Argument: Numeric file descriptor of open TCP connection.
+   Also see: -j, -J.
+   -G arg Y 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.
+   -H N Suppress program startup Herald and greeting.
+   -I N 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.
+   -J arg N "Be like Telnet." Like -j but implies -E.
+   Argument: IP hostname/address optionally followed by service.
+   NOTE: C-Kermit also has a separate Telnet command-line personality,
+   with regular Telnet-like command-line syntax. [57]More about this
+   below.
+   -L N Recursive directory descent for files in -s option.
+   -M arg N My user name (for use with Telnet, Rlogin, FTP, etc).
+   Equivalent to the SET LOGIN USER command.
+   Argument: Username string.
+   -O Y (Uppercase letter O) Be a server for One command only. Also see:
+   -x.
+   -P N Don't convert file (Path) names of transferred files. Equivalent
+   to SET FILE NAMES LITERAL.
+   -Q N Quick Kermit protocol settings. Equivalent to the FAST command.
+   This is the default in C-Kermit 7.0 and later.
+   -R N Remote-only (this just makes IF REMOTE true).
+   -S N Stay (enter command parser after action options).
+   -T N Force Text mode for file transfer; implies -V. Equivalent to SET
+   TRANSFER MODE MANUAL, SET FILE TYPE TEXT.
+   -V N Disable automatic per-file text/binary switching. Equivalent to
+   SET TRANSFER MODE MANUAL.
+   -Y N Skip (don't execute) the initialization file.
+   -a arg N As-name for file(s) in -s, -r, or -g.
+   Argument: As-name string (alternative filename). When receiving files,
+   this can be a directory name.
+   -b arg N Speed for serial device. Equivalent to SET SPEED.
+   Argument: Numeric Bits per second for serial connections.
+   -c Y Enter Connect state before transferring files.
+   -d N Create a debug.log file with detailed debugging information (a
+   second -d adds timestamps). Equivalent to LOG DEBUG but takes effect
+   sooner.
+   -e arg N Maximum length for incoming Kermit file-transfer packets.
+   Equivalent to SET RECEIVE PACKET-LENGTH.
+   Argument: Length in bytes.
+   -f Y Send a FINISH command to a Kermit server.
+   -g arg N 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.
+   -h Y Print Help text for single-letter command-line options (pipe thru
+   'more' to prevent scrolling).
+   -i N Force binary (Image) mode for file transfer; implies -V.
+   Equivalent to SET TRANSFER MODE MANUAL, SET FILE TYPE BINARY.
+   -j arg N 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.
+   -k Y Receive file(s) to standard output, which normally would be piped
+   to another process.
+   Also see: -r, -G.
+   -l arg N (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.
+   -m arg N 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".
+   -n Y Enter Connect state after transferring files (historical).
+   -p arg N Parity. Equivalent to the SET PARITY command.
+   Argument: One of the following: e(ven), o(dd), m(ark), n(one),
+   s(pace).
+   -q N Quiet (suppress most messages). Equivalent to SET QUIET ON.
+   -r Y Receive file(s). Equivalent to the RECEIVE command.
+   Argument: (none, but see -a)
+   -s arg N Send file(s).
+   Argument: One or more local file specifications. Equivalent to the
+   SEND command.
+   Also see: -a.
+   -t N (Historical) Xon (Ctrl-Q) Turnaround character for half-duplex
+   connections (used on serial linemode connections to old mainframes).
+   Equivalent to SET DUPLEX HALF, SET HANDSHAKE XON.
+   -v arg N Window size for Kermit protocol (ignored when streaming).
+   Equivalanet to SET WINDOW-SIZE.
+   Argument: Number, 1 to 32.
+   -w N Incoming files Write over existing files. Equivalent to SET FILE
+   COLLISION OVERWRITE.
+   -x Y Enter server mode. Equivalent to the SERVER command. Also see:
+   -O.
+   -y arg N Alternative initialization file.
+   Argument: Filename.
+   -z N Force foreground behavior. To be used in case Kermit doesn't
+   automatically sense its foreground status. Equivalent to the SET
+   BACKGROUND OFF command.
+   
+   Extended command-line options (necessary because single-letter 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:
+   Option Description
+   --bannerfile:filename File to display upon startup or IKSD login.
+   --cdfile:filename File to be sent for display to the client when
+   server changes directory (filename is relative to the changed-to
+   directory).
+   --cdmessage:{on,off} Enable/disable the server CD message feature.
+   --help Prints usage message for extended options.
+   --helpfile:filename Designates a file containing custom text to
+   replace the top-level HELP command.
+   --nointerrupts Disables keyboard interrupts.
+   --noperms Disables the Kermit protocol file Permissions attribute, to
+   prevent transmission of file permissions (protection) from sender to
+   receiver.
+   
+   Plus several other [58]IKSD-Only options.
+   
+   See the [59]file-transfer section for examples of command-line
+   invocation.
+    ________________________________________________________________________
+  
+  COMMAND LANGUAGE [ [60]Top ] [ [61]Contents ] [ [62]Next ] [ [63]Previous ]
+  
+     * [64]Command Files, Macros, and Scripts
+     * [65]Command List
+       
+   C-Kermit's interactive command language is the subject of a
+   [66]622-page 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-Kermit's interactive command
+   prompt:
+   
+  $ kermit
+  (/current/directory) C-Kermit>
+
+   Begin by typing "help" (and then press the Return or Enter key) for a
+   top-level 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).
+   
+   Interactive commands are composed mainly of regular English words,
+   usually in the form of imperative sentences, such as:
+   
+  send oofa.txt
+
+   which tells Kermit to send (transfer) the file whose name is oofa.txt,
+   or:
+   
+  set transfer mode automatic
+
+   which sets Kermit's "transfer mode" to "automatic" (whatever that
+   means).
+   
+   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.
+   
+   C-Kermit has hundreds of commands, and they can be issued in infinite
+   variety and combinations, including commands for:
+   
+     * Making connections (SET LINE, DIAL, TELNET, SSH, FTP, CONNECT,
+       ...)
+     * Breaking connections (HANGUP, CLOSE)
+     * Transferring files (SEND, GET, RECEIVE, MOVE, RESEND, ...)
+     * Establishing preferences (SET)
+     * Displaying preferences (SHOW)
+     * Managing local files (CD, DELETE, MKDIR, DIRECTORY, RENAME, TYPE,
+       ...)
+     * Managing remote files (RCD, RDEL, RMKDIR, RDIR, ...)
+     * Using local files (FOPEN, FCLOSE, FREAD, FWRITE)
+     * Programming (TAKE, DEFINE, IF, FOR, WHILE, SWITCH, DECLARE, ...)
+     * Interacting with the user (ECHO, ASK, ...)
+     * Interacting with a remote computer (INPUT, OUTPUT, ...)
+     * Interacting with local programs (RUN, EXEC, PTY, ...)
+     * Logging things (LOG SESSION, LOG PACKETS, LOG DEBUG, ...)
+       
+   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-in and
+   user-defined functions, string manipulation, pattern matching, block
+   structure, scoping, recursion, and all the rest. To get a list of all
+   C-Kermit'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:
+   
+  help send
+
+   The command interruption character is Ctrl-C (hold down the Ctrl key
+   and press the C key).
+   
+   The command language "escape character", used to introduce variable
+   names, function invocations, and so on, is backslash (\). If you need
+   to include a literal backslash in a command, type two of them, e.g.:
+   
+  get c:\\k95\\k95custom.ini
+
+  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:
+   
+  (/current/dir) C-Kermit> take commandfile
+
+   (where "commandfile" is the name of the command file). Please don't
+   pipe a command file into Kermit's standard input (which might or might
+   not work); if you have Kermit commands in a file, tell Kermit to TAKE
+   the file.
+   
+   In Unix only, a Kermit command file can also be executed directly by
+   including a "kerbang" line as the first line of the file:
+   
+  #!/usr/local/bin/kermit +
+
+   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:
+   
+  chmod +x commandfile
+
+   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):
+   
+  #!/usr/local/bin/kermit +
+  if defined \%1 echo "Argument 1: \%1"
+  if defined \%2 echo "Argument 2: \%2"
+  if defined \%3 echo "Argument 3: \%3"
+  if defined \%4 echo "etc..."
+  exit
+
+   If this file is stored in your current directory as "commandfile",
+   then:
+   
+  ./commandfile one two three four five
+
+   prints:
+   
+  Argument 1: one
+  Argument 2: two
+  Argument 3: three
+  etc...
+
+   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. \%1
+   is the first argument, \%2 the second, and so on.
+   
+   You can also create your own commands by defining named macros
+   composed of other Kermit commands (or macros). Here's a simple
+   example:
+   
+  define mydial {
+      set modem type usrobotics
+      set port /dev/ttyS0
+      if fail end 1
+      set speed 57600
+      dial \%1
+      if success connect
+  }
+
+   This shows how you can combine many commands into one command,
+   "mydial" in this case (you can use any name you like, provided it does
+   not clash with the name of a built-in command). When this macro
+   definition is in effect, you can type commands like:
+   
+  mydial 7654321
+
+   and it executes all the commands in macro definition, substituting the
+   first operand ("7654321") for the formal parameter ("\%1") in the
+   definition. This saves you from having to type lots of commands every
+   time you want to make a modem call.
+   
+   One way to have the macro definition in effect is to type the
+   definition at the Kermit prompt. Another way is to store the
+   definition in a file and TAKE the file. If you want the the definition
+   to be in effect automatically every time you start Kermit, put the
+   definition in your initialization or customization file (explained
+   [67]below).
+   
+   Here's a somewhat more ambitious example:
+   
+  define mydelete {
+      local trash
+      assign trash \v(home)trashcan/
+      if not defined \%1 end 1 "Delete what?"
+      if wild \%1 end 1 "Deleting multiple files is too scary"
+      if not exist \%1 end 1 "I can't find \%1"
+      if not directory \m(trash) {
+          mkdir \m(trash)
+          if fail end 1 "No trash can"
+      }
+      rename /list \%1 \m(trash)
+  }
+  define myundelete {
+      local trash
+      assign trash \v(home)trashcan/
+      if not defined \%1 end 1 "Undelete what?"
+      if wild \%1 end 1 "Undeleting multiple files is too hard"
+      if not directory \m(trash) end 1 "No trash can"
+      if not exist \m(trash)\%1 end 1 "I can't find \%1 in trash can"
+      rename /list \m(trash)\%1 .
+  }
+
+   These 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,
+   they can check them and make other kinds of decisions, and the
+   commands themselves are relatively intuitive and intelligible.
+   
+   If you put the above lines into your initialization or customization
+   file, 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.)
+   
+   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
+   
+  take \v(home).kermrc
+
+   at the desired spot in the script. By the way, \v(xxx) is a built-in
+   variable (xxx is the variable name, "home" in this case). To see what
+   built-in variables are available, type "show variables" at the
+   C-Kermit prompt. To see what else you can show, type "show ?". \m(xxx)
+   is a user defined variable (strictly speaking, it is a macro used as a
+   variable).
+   
+  Command List
+  
+   C-Kermit has more than 200 top-level 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-level 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.
+   
+   Optional fields are shown in [ italicized 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:
+   
+  send /recursive /larger:10000 /after:-1week /except:*.txt *
+
+   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".
+   
+   Basic Commands
+          HELP Requests top-level help.
+          HELP command Requests help about the given command.
+          INTRODUCTION Requests a brief introduction to C-Kermit.
+          LICENSE Displays the C-Kermit software copyright and license.
+          VERSION Displays C-Kermit's version number.
+          EXIT [ number ] Exits from Kermit with the given status code.
+          Synonyms: QUIT, E, Q.
+          TAKE filename [ parameters... ] Executes commands from the
+          given file.
+          LOG item [ filename ] Keeps a log of the given item in the
+          given file.
+          [ DO ] macro [ parameters... ]    Executes commands from the
+          given macro.
+          SET parameter value Sets the given parameter to the given
+          value.
+          SHOW category Shows settings in a given category.
+          STATUS Tells whether previous command succeeded or failed.
+          DATE [ date-and/or-time ] Shows current date-time or interprets
+          given date-time.
+          RUN [ extern-command [ parameters... ] Runs the given external
+          command. Synonym: !.
+          EXEC [ extern-command [ params... ] Kermit overlays itself with
+          the given command.
+          SUSPEND Stops Kermit and puts it in the background. Synonym: Z.
+          
+   Local File Management
+          TYPE [ options ] filename Displays the contents of the given
+          file.
+          MORE [ options ] filename Equivalent to TYPE /PAGE (pause after
+          each screenful).
+          CAT [ options ] filename Equivalent to TYPE /NOPAGE.
+          HEAD [ options ] filename Displays the first few lines of a
+          given file.
+          TAIL [ options ] filename Displays the last few lines of a
+          given file.
+          GREP [ options ] pattern filespec Displays lines from files
+          that match the pattern. Synonym: FIND.
+          DIRECTORY [ options ] [ filespec ] Lists files (built-in, many
+          options).
+          LS [ options ] [ filespec ] Lists files (runs external "ls"
+          command).
+          DELETE [ options ] [ filespec ] Deletes files. Synonym: RM.
+          PURGE [ options ] [ filespec ] Removes backup (*.~n~) files.
+          COPY [ options ] [ filespecs... ] Copies files. Synonym: CP.
+          RENAME [ options ] [ filespecs... ] Renames files. Synonym: MV.
+          CHMOD [ options ] [ filespecs... ] Changes permissions of
+          files.
+          TRANSLATE filename charsets filename ] Converts file's
+          character set. Synonym: XLATE.
+          CD Changes your working directory to your home directory.
+          CD directory Changes your working directory to the one given.
+          CDUP Changes your working directory one level up.
+          PWD Displays your working directory.
+          BACK Returns to your previous working directory.
+          MKDIR [ directory ] Creates a directory.
+          RMDIR [ directory ] Removes a directory.
+          
+   Making Connections
+          SET LINE [ options ] devicename        Opens the named serial
+          port. Synonym: SET PORT.
+          OPEN LINE [ options ] devicename Same as SET LINE. Synonym:
+          OPEN PORT.
+          SET MODEM TYPE [ name ] Tells Kermit what kind of modem is on
+          the port.
+          DIAL [ number ] Tells Kermit to dial the given phone number
+          with the modem.
+          REDIAL Redials the most recently dialed phone number.
+          ANSWER Waits for and answers an incoming call on the modem.
+          AUTHENTICATE [ parameters... ] Performs secure authentication
+          on a TCP/IP connection.
+          SET NETWORK TYPE { TCP/IP, X.25, ... } Selects network type for
+          subsequent SET HOST commands.
+          SET HOST [ options ] host [ port ] Opens a network connection
+          to the given host and port.
+          SET HOST [ options ] * port Waits for an incoming TCP/IP
+          connection on the given port.
+          TELNET [ options ] host Opens a Telnet connection to the host
+          and enters Connect state.
+          RLOGIN [ options ] host Opens an Rlogin connection to the host
+          and enters Connect state.
+          IKSD [ options ] host Opens a connection to an Internet Kermit
+          Service.
+          SSH [ options ] host Opens an SSH connection to the host and
+          enters Connect state.
+          FTP OPEN host [ options ] Opens an FTP connection to the host.
+          HTTP [ options ] OPEN host Opens an HTTP connection to the
+          host.
+          PTY external-command Runs the command on a pseudoterminal as if
+          it were a connection.
+          PIPE external-command Runs the command through a pipe as if it
+          were a connection.
+          
+   Using Connections
+          CONNECT [ options ]                    Enters Connect
+          (terminal) state. Synonym: C.
+          REDIRECT command Redirects the given external command over the
+          connection.
+          TELOPT command Sends a Telnet protocol command (Telnet
+          connections only).
+          Ctrl-\C "Escapes back" from Connect state to Command state.
+          Ctrl-\B (In Connect state) Sends a BREAK signal (serial or
+          Telnet).
+          Ctrl-\! (In Connect state) Enters inferior shell; "exit" to
+          return.
+          Ctrl-\? (In Connect state) Shows a menu of other escape-level
+          options.
+          Ctrl-\Ctrl-\ (In Connect state) Type two Ctrl-Backslashes to
+          send one of them.
+          SET ESCAPE [ character ] Changes Kermit's Connect-state escape
+          character.
+          
+   Closing Connections
+          HANGUP Hangs up the currently open serial-port or network
+          connection.
+          CLOSE Closes the currently open serial-port or network
+          connection.
+          SET LINE (with no devicename)          Closes the currently
+          open serial-port or network connection.
+          SET HOST (with no hostname) Closes the currently open
+          serial-port or network connection.
+          FTP CLOSE Closes the currently open FTP connection.
+          HTTP CLOSE Closes the currently open HTTP connection.
+          EXIT Also closes all connections. Synonym: QUIT.
+          SET EXIT WARNING OFF Suppresses warning about open connections
+          on exit or close.
+          
+   File Transfer
+          SEND [ options ] filename [ as-name ]  Sends the given file.
+          Synonym: S.
+          SEND [ options ] filespec Sends all files that match.
+          RESEND [ options ] filespec Resumes an interupted SEND from the
+          point of failure.
+          RECEIVE [ options ] [ as-name ] Waits passively for files to
+          arrive. Synonym: R.
+          LOG TRANSACTIONS [ filename ] Keeps a record of file transfers.
+          FAST Use fast file-transfer settings (default).
+          CAUTIOUS Use cautious and less fast file-transfer settings.
+          ROBUST Use ultra-conservative and slow file-transfer settings.
+          STATISTICS [ options ] Gives statistics about the most recent
+          file transfer.
+          WHERE After transfer: "Where did my files go?".
+          TRANSMIT [ options ] [ filename ] Sends file without protocol.
+          Synonym: XMIT.
+          LOG SESSION [ filename ] Captures remote text or files without
+          protocol.
+          SET PROTOCOL [ name... ] Tells Kermit to use an external
+          file-transfer protocol.
+          FTP { PUT, MPUT, GET, MGET, ... } FTP client commands.
+          HTTP { PUT, GET, HEAD, POST, ... } HTTP client commands.
+          
+   Kermit Server
+          ENABLE, DISABLE                        Controls which features
+          can be used by clients.
+          SET SERVER Sets parameters prior to entering Server state.
+          SERVER Enters Server state.
+          
+   Client of Kermit or FTP Server
+          [ REMOTE ] LOGIN [ user password ] Logs in to a Kermit server
+          or IKSD that requires it.
+          [ REMOTE ] LOGOUT Logs out from a Kermit server or IKSD.
+          SEND [ options ] filename [ as-name ]  Sends the given file to
+          the server. Synonyms: S, PUT.
+          SEND [ options ] filespec Sends all files that match.
+          RESEND [ options ] filespec Resumes an interupted SEND from the
+          point of failure.
+          GET [ options ] remote-filespec Asks the server to send the
+          given files. Synonym: G.
+          REGET [ options ] remote-filespec Resumes an interrupted GET
+          from the point of failure.
+          REMOTE CD [ directory ] Asks server to change its working
+          directory. Synonym: RCD.
+          REMOTE PWD [ directory ] Asks server to display its working
+          directory. Synonym: RPWD.
+          REMOTE DIRECTORY [ filespec... ] Asks server to send a
+          directory listing. Synonym: RDIR.
+          REMOTE DELETE [ filespec... ] Asks server to delete files.
+          Synonym: RDEL.
+          REMOTE [ command... ] (Many other commands: "remote ?" for a
+          list).
+          MAIL [ options ] filespec Sends file(s) to be delivered as
+          e-mail (Kermit only).
+          FINISH Asks the server to exit server state (Kermit only).
+          BYE Asks the server to log out and close the connection.
+          
+   Script Programming
+          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 [68]manual and supplements, and/or
+          visit the [69]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.
+          
+   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
+   [70]full documentation.
+   
+   Use question mark to feel your way through an unfamiliar command, as
+   in this example (the part you type is underlined):
+   
+  C-Kermit> remote ? One of the following:
+   assign     delete     help       login      print      rename     space
+   cd         directory  host       logout     pwd        rmdir      type
+   copy       exit       kermit     mkdir      query      set        who
+  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>
+
+   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'.
+   
+   [ [71]Kermit Home ] [ [72]C-Kermit Home ] [ [73]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  INITIALIZATION FILE [ [74]Top ] [ [75]Contents ] [ [76]Next ] [ [77]Previous
+  ]
+  
+   In its default configuration, C-Kermit executes commands from a file
+   called .kermrc in your home directory when it starts, unless it is
+   given the -Y or -y command-line option. Custom configurations might
+   substitute a shared system-wide 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.
+   
+   Since execution of the initialization file (at least the standard one)
+   makes C-Kermit 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 -- 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-Kermit directly when you don't.
+   
+   To put it another way... We still distribute the standard
+   initialization file since it's featured in the manual and backwards
+   compatibility is important to us. But there's no harm in not using it
+   if you don't need the stuff that's in it (services directory, dialing
+   directory, network directory, and associated macro definitions). On
+   the other hand, if there are settings or macros you want in effect
+   EVERY time you use Kermit, the initialization file (or the
+   customization file it chains to) is the place to put them, because
+   that's the only place Kermit looks for them automatically each time
+   you start it.
+   
+   [ [78]Kermit Home ] [ [79]C-Kermit Home ] [ [80]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  MODES OF OPERATION [ [81]Top ] [ [82]Contents ] [ [83]Next ] [ [84]Previous ]
+  
+   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 the remote
+   computer and your keyboard and screen. The remote Kermit is the
+   file-transfer partner to the local Kermit and communicates only
+   through its standard input and output.
+   
+   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.
+   
+   Command state
+          
+          In this state, Kermit reads commands from:
+          
+          + Your keyboard; or:
+          + A file, or:
+          + A macro definition.
+            
+          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.
+          
+   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.
+          
+   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, RLOGIN, or IKSD command. You can return to command
+          state by logging out of the remote computer, or by typing:
+          
+  Ctrl-\c
+
+          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-level commands are also
+          provided; type Ctrl-\? for a list. For example, you can enter
+          Shell state with:
+          
+  Ctrl-\!
+
+          To send a Ctrl-\ to the host while in Connect state, type two
+          of them in a row. See HELP CONNECT and HELP SET ESCAPE for more
+          info.
+          
+   Local file-transfer 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-related 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-keystroke commands are accepted:
+          
+            X Interrupt the current file and go on to the next (if any).
+            Z Interrupt the current file and skip all the rest.
+            E Like Z but uses a "stronger" protocol (use if X or Z don't
+          work).
+            Ctrl-C   Interrupt file-transfer mode (use if Z or E don't
+          work).
+          
+          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).
+          
+   Remote file-transfer state
+          
+          In this state, Kermit is exchanging file-transfer 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-transfer 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-\ C) and type
+          "e-packet" and then press the Return or Enter key; this forces
+          a fatal Kermit protocol error.
+          
+   Remote Server state
+          
+          This is like Remote File-transfer 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.
+          
+   Local Server state
+          
+          Like Remote-Server state, but in local mode, and therefore with
+          its file-transfer display showing, and listening for single-key
+          commands, as in Local File-transfer state. Usually this state
+          is entered automatically when a remote Kermit program gives a
+          GET command.
+          
+   C-Kermit, Kermit 95, and MS-DOS Kermit all can switch automatically
+   from Connect state to Local File-transfer 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.
+   
+   Note that C-Kermit 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-Kermit.
+   Kermit 95 and MS-DOS Kermit, on the other hand, are true terminal
+   emulators. Why is C-Kermit not a terminal emulator? [85]CLICK HERE to
+   read about it.
+   
+   [ [86]Kermit Home ] [ [87]C-Kermit Home ] [ [88]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  MAKING CONNECTIONS [ [89]Top ] [ [90]Contents ] [ [91]Next ] [ [92]Previous ]
+  
+   Here is how to make different kinds of connections using interactive
+   Kermit commands (as noted above, you can also make connections with
+   command-line 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.
+   
+   Making a Telnet Connection
+          
+          At the C-Kermit command prompt, simply type:
+          
+  telnet foo.bar.com         ; Substitute desired host name or address.
+  telnet xyzcorp.com 3000    ; You can also include a port number.
+
+          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 [93]IKSD section
+          below.
+          
+   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:
+          
+  rlogin foo.bar.com         ; Substitute desired host name or address.
+
+          More info: HELP RLOGIN.
+          
+   Making an SSH Connection
+          
+          Unlike Telnet and Rlogin, SSH connections are not built-in, but
+          handled by running your external SSH client through a
+          pseudoterminal. Using C-Kermit to control the SSH client gives
+          you all of Kermit's features (file transfer, character-set
+          conversion, scripting, etc) over SSH.
+          
+  ssh foo.bar.com            ; Substitute desired host name or address.
+
+          More info: HELP SSH, HELP SET SSH.
+          
+   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-through) modem cable, and to the telephone jack with
+          a telephone cable, and that it's turned on. Then use these
+          commands:
+          
+  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
+
+          Type "set modem type ?" for a list of supported modem types. If
+          you omit the SET MODEM TYPE command, the default type is
+          "generic-high-speed", which should work for most modern
+          AT-command-set 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.
+          
+          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:
+          
+  set host ts.xxx.com 2000   ; Terminal-server and port
+  set modem type usrobotics  ; Or other supported type
+  set dial method tone       ; (or pulse)
+  dial 7654321               ; Dial the desired number
+
+          If the terminal server supports the Telnet Com Port Option,
+          [94]RFC 2217, you can also give serial-port 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.
+          
+          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.
+          
+   Direct Serial Port
+          
+          Connect the two computers, A and B, with a null modem cable (or
+          two modem cables interconnected with a null-modem adapter or
+          modem eliminator). From Computer A:
+          
+  set modem type none        ; There is no modem
+  set line /dev/ttyS0        ; Specify device name
+  set carrier-watch off      ; If DTR and CD are not cross-connected
+  set speed 57600            ; Or other desired speed
+  set flow rts/cts           ; If RTS and CTS are cross-connected
+  set flow xon/xoff          ; If you can't use RTS/CTS
+  set parity even            ; (or "mark" or "space", if necessary)
+  set stop-bits 2            ; (rarely necessary)
+  connect                    ; Enter Connect (terminal) state
+
+          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.
+          
+   With modems or direct serial connections, you might also have to "set
+   parity even" (or "mark" or "space") if it's a 7-bit connection.
+   
+   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 [95]FTP or
+   HTTP session. Each connection type can be customized to any desired
+   degree, scripted, logged, you name it. See the manual.
+   
+   NOTE: On selected platforms, C-Kermit also can make X.25 connections.
+   See the manual for details.
+   
+   [ [96]Kermit Home ] [ [97]C-Kermit Home ] [ [98]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  TRANSFERRING FILES WITH KERMIT [ [99]Top ] [ [100]Contents ] [ [101]Next ] [
+  [102]Previous ]
+  
+     * [103]Downloading Files
+     * [104]Uploading Files
+     * [105]Kermit Transfers the Old-Fashioned Way
+     * [106]If File Transfer Fails
+     * [107]Advanced Kermit File Transfer Features
+     * [108]Non-Kermit File Transfer
+       
+   There is a [109]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-line 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-Kermit-Project Kermit protocol implementations really ARE
+   slow. The best file-transfer partners for C-Kermit are: another copy
+   of [110]C-Kermit (7.0 or later) and [111]Kermit 95. These combinations
+   work well and they work fast by default. MS-DOS Kermit is good too,
+   but you have to tell it to go fast (by giving it the FAST command).
+   
+   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.
+   
+   And plus, C-Kermit and K95 also switch 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.
+   
+   What all of these words add up to is that now, when you use up-to-date
+   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.
+   
+   Downloading Files
+          
+          Let's say you have [112]Kermit 95, [113]C-Kermit, or
+          [114]MS-DOS Kermit on your desktop computer, with a connection
+          to a Unix computer that has C-Kermit 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:
+          
+  kermit -s oofa.txt
+
+          (where oofa.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:
+          
+  kermit -s oofa.txt oofa.zip oofa.html oofa.tar.gz
+
+          and/or you can use wildcards to send groups of files:
+          
+  kermit -s oofa.*
+
+          If you want to send a file under an assumed name, use:
+          
+  kermit -s friday.txt -a today.txt
+
+          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-connecting, text/binary mode switching. Almost too easy,
+          right?
+          
+   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:
+          
+  kermit -g oofa.txt
+
+          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.
+          
+          If you want to upload multiple files, you have have use shell
+          quoting rules, since these aren't local files:
+          
+  kermit -g "oofa.txt oofa.zip oofa.html oofa.tar.gz"
+  kermit -g "oofa.*"
+
+          If you want to upload a file but store it under a different
+          name, use:
+          
+  kermit -g friday.txt -a today.txt
+
+   Kermit Transfers the Old-Fashioned 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.
+          
+          To download a file, type:
+          
+  kermit -s filename
+
+          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.
+          
+          To upload a file, type:
+          
+  kermit -r
+
+          on the host (rather than "kermit -g"). This tells C-Kermit 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.
+          
+   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:
+          
+        FAST
+                Use fast file-transfer settings. This has been the
+                default since C-Kermit 7.0 now that most modern computers
+                and connections support it. If transfers fail with fast
+                settings, try . . .
+                
+        CAUTIOUS
+                Use cautious but not paranoid settings. File transfers,
+                if they work, will go at medium speed. If not, try . . .
+                
+        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-Kermit'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-bit connection.
+                
+          Obviously the success and performance of a file transfer also
+          depends on C-Kermit's file transfer partner. Up-to-date, real
+          [115]Kermit Project partners are recommended because they
+          contain the best Kermit protocol implementations and because
+          [116]we can support them in case of trouble.
+          
+          If you still have trouble, consult Chapter 10 of [117]Using
+          C-Kermit, or send email to [118]kermit-support@columbia.edu.
+          
+   Advanced Kermit File-Transfer 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 [119]manual and updates are
+          for. Here are a few topics you can explore if you're interested
+          by Typing HELP for the listed commands:
+          
+        Logging transfers:
+                LOG TRANSACTIONS (HELP LOG)
+                
+        Automatic per-file text/binary mode switching:
+                SET TRANSFER MODE { AUTOMATIC, MANUAL } (HELP SET
+                TRANSFER).
+                
+        Cross-platform recursive directory tree transfer:
+                SEND /RECURSIVE, GET /RECURSIVE (HELP SEND, HELP GET).
+                
+        File collision options:
+                SET FILE COLLISION { OVERWRITE, BACKUP, DISCARD, ... }
+                (HELP SET FILE).
+                
+        Update mode (only transfer files that changed since last time):
+                SET FILE COLLISION UPDATE (HELP SET FILE).
+                
+        Filename selection patterns:
+                (HELP WILDCARD).
+                
+        Flexible file selection:
+                SEND (or GET) /BEFORE /AFTER /LARGER /SMALLER /TYPE
+                /EXCEPT, ...
+                
+        Character-set conversion:
+                SET { FILE, TRANSFER } CHARACTER-SET, ASSOCIATE, ...
+                
+        File/Pathname control:
+                SET { SEND, RECEIVE } PATHNAMES, SET FILE NAMES.
+                
+        Atomic file movement:
+                SEND (or GET) /DELETE /RENAME /MOVE-TO
+                
+        Transferring to/from standard i/o of other commands:
+                SEND (or GET) /COMMAND
+                
+        Recovery of interrupted transfer from point of failure:
+                RESEND, REGET (HELP RESEND, HELP REGET).
+                
+   Non-Kermit File Transfer
+          
+          You can also use C-Kermit to transfer files with FTP or HTTP
+          Internet protocols; [120]see below.
+          
+          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.
+          
+          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).
+          
+   [ [121]Kermit Home ] [ [122]C-Kermit Home ] [ [123]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  KERMIT CLIENT/SERVER CONNECTIONS [ [124]Top ] [ [125]Contents ] [ [126]Next ]
+  [ [127]Previous ]
+  
+   On any kind of connection you can make with Kermit -- serial, TCP/IP,
+   X.25, etc -- you can set up a convenient client/server relationship
+   between your Kermit client (the one that made the connection) and the
+   Kermit program on the far end of the connection (the remote Kermit) by
+   putting the remote Kermit in server mode. This is normally done by
+   giving it a SERVER command, or by starting it with the -x command-line
+   option. In some cases ([128]Internet Kermit Service, SSH connections
+   to a Kermit subsystem, or specially configured hosts), there is
+   already a Kermit server waiting on the far end. Here is a quick
+   synopsis of the commands you can give to the client for interacting
+   with the server:
+   
+   SEND [ switches ] filename
+          Sends the named file to the server. The filename can include
+          wildcards. Lots of switches are available for file selection,
+          etc. Type HELP SEND at the client prompt for details.
+          
+   GET [ switches ] filename
+          Asks the server to send the named file. The filename can
+          include wildcards. Type HELP GET at the client prompt for
+          details.
+          
+   BYE
+          Terminates the server and closes your connection to it.
+          
+   FINISH
+          Terminates the server. If you started the server yourself, this
+          leaves the remote host at its shell prompt. If it was a
+          dedicated server (such as IKSD or an SSH subsystem), FINISH is
+          equivalent to BYE.
+          
+   SET LOCUS { LOCAL, REMOTE, AUTO }
+          (C-Kermit 8.0.201 and later, K95 1.1.21 and later) This tells
+          the client whether file-management commands like CD, PWD,
+          DIRECTORY, DELETE, MKDIR, etc, should be executed locally or by
+          the server. In this type of connection, the default is LOCAL.
+          Use SET LOCUS REMOTE if you want Kermit to behave like an FTP
+          client, in which case these commands are executed remotely, and
+          their local versions must have an L prefix: LCD, LPWD,
+          LDIRECTORY, etc. When LOCUS is LOCAL, then the remote versions
+          must have an R prefix: RCD, RPWD, RDIRECTORY, etc. HELP SET
+          LOCUS for details. SHOW COMMAND to see current locus.
+          
+   The following commands are affected by SET LOCUS:
+   
+   CD, LCD, RCD
+   Change (working, current) directory. HELP CD for details.
+   
+   CDUP, LCDUP, RCDUP
+   CD one level up.
+   
+   DIRECTORY, LDIRECTORY, RDIRECTORY
+   Produce a directory listing. Many options are available for local
+   listings. HELP DIRECTORY for details.
+   
+   DELETE, LDELETE, RDELETE
+   Deletes files or directories. Many options available, HELP DELETE.
+   
+   RENAME, LRENAME, RRENAME
+   Renames files or directories. Many options available, HELP RENAME.
+   
+   MKDIR, LMKDIR, RMKDIR
+   Creates a directory. HELP MKDIR.
+   
+   RMDIR, LRMDIR, RRMDIR
+   Removes a directory. HELP RMDIR. There are dozens -- maybe hundreds --
+   of other commands, described in the built-in help, on the website,
+   and/or in the published or online manuals. But even if you don't have
+   access to documentation, you can "set locus remote" and then use
+   pretty much the same commands you would use with any FTP client.
+   
+   [ [129]Kermit Home ] [ [130]C-Kermit Home ] [ [131]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  KERMIT'S BUILT-IN FTP AND HTTP CLIENTS [ [132]Top ] [ [133]Contents ] [
+  [134]Next ] [ [135]Previous ]
+  
+   Kermit's FTP client is like the regular Unix FTP client that you're
+   used to, but with some differences:
+   
+     * It has lots more commands and features.
+     * You can have an FTP session and a regular Kermit serial or Telnet
+       session open at the same time.
+     * FTP sessions can be fully automated.
+       
+   By default Kermit's FTP client tries its best to present the same user
+   interface as a regular FTP client: PUT, GET, DIR, CD, BYE, etc, should
+   work the same, even though some of these commands have different
+   meaning in Kermit-to-Kermit connections; for example, CD, DIR, RENAME,
+   etc, in Kermit act locally, whereas in FTP they are commands for the
+   server. This might cause some confusion, but as in all things Kermit,
+   you have total control:
+   
+     * The [136]SET LOCUS command lets you specify where file management
+       commands should be executed -- locally or remotely -- for any kind
+       of connection.
+     * Any FTP command can be prefixed with the word "FTP" to remove any
+       ambiguity.
+       
+   Pending publication of the next edition of the manual, the Kermit FTP
+   client is thoroughly documented at the Kermit Project website:
+   
+  [137]http://www.columbia.edu/kermit/ftpclient.html
+
+   You also can use HELP FTP and HELP SET FTP to get descriptions of
+   Kermit's FTP-related commands.
+   
+   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
+   [138]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.
+   
+   [ [139]Kermit Home ] [ [140]C-Kermit Home ] [ [141]C-Kermit FAQ ] [
+   [142]FTP Client ] [ [143]HTTP Client ]
+    ________________________________________________________________________
+  
+  INTERNET KERMIT SERVICE [ [144]Top ] [ [145]Contents ] [ [146]Next ] [
+  [147]Previous ]
+  
+   C-Kermit 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-Kermit can be an Internet Kermit Server, or it can be a client of an
+   IKSD. You can make connections from C-Kermit to an IKSD with any of
+   the following commands:
+   
+  telnet foo.bar.edu 1649
+  telnet foo.bar.edu kermit   ; if "kermit" is listed in /etc/services
+  iksd foo.bar.edu
+
+   The IKSD command is equivalent to a TELNET command specifying port
+   1649. For more information about making and using connections to an
+   IKSD, see:
+   
+  [148]http://www.columbia.edu/kermit/cuiksd.html
+
+   You can run an Internet Kermit Service on your own computer too (if
+   you are the system administrator). For instructions, see:
+   
+  [149]http://www.columbia.edu/kermit/iksd.html
+
+   [ [150]Kermit Home ] [ [151]C-Kermit Home ] [ [152]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  SECURITY [ [153]Top ] [ [154]Contents ] [ [155]Next ] [ [156]Previous ]
+  
+   All of C-Kermit's built-in TCP/IP networking methods (Telnet, Rlogin,
+   IKSD, FTP, and HTTP) can be secured by one or more of the following
+   IETF-approved methods:
+   
+     * MIT Kerberos IV
+     * MIT Kerberos V
+     * SSL/TLS
+     * Stanford SRP
+       
+   For complete instructions see:
+   
+  [157]http://www.columbia.edu/kermit/security.html
+
+   And as noted previously, you can also make SSH connections with
+   C-Kermit if you already have an SSH client installed.
+   
+   [ [158]Kermit Home ] [ [159]C-Kermit Home ] [ [160]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  ALTERNATIVE COMMAND-LINE PERSONALITIES [ [161]Top ] [ [162]Contents ] [
+  [163]Next ] [ [164]Previous ]
+  
+   When invoked as "kermit" or any other name besides any of the special
+   ones, C-Kermit has the command-line options described above in the
+   [165]OPTIONS section. However, if you invoke C-Kermit using any of the
+   following names:
+   
+     telnet  Telnet client
+     ftp     FTP client
+     http    HTTP client
+     https   Secure HTTP client
+   
+   Kermit's command-line personality changes to match. This can be done
+   (among other ways) with symbolic links (symlinks). For example, if you
+   want C-Kermit 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:
+   
+  ln -s /usr/local/bin/kermit telnet
+
+   Now when you give a "telnet" command, you are invoking Kermit instead,
+   but with its Telnet command-line personality so, for example:
+   
+  telnet xyzcorp.com
+
+   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-personality command-line options, which are intended to be as
+   compatible as possible with the regular Telnet client.
+   
+   Similarly for FTP:
+   
+  ln -s /usr/local/bin/kermit ftp
+
+   And now type "ftp -h" to see its command-line options, and use command
+   lines just like you would give your regular FTP client:
+   
+  ftp -n xyzcorp.com
+
+   but with additional options allowing an entire session to be specified
+   on the command line, as explained in the C-Kermit [166]FTP client
+   documentation.
+   
+   And similarly for HTTP:
+   
+  ln -s /usr/local/bin/kermit http
+  ./http -h
+  ./http www.columbia.edu -g kermit/index.html
+
+   Finally, if Kermit's first command-line 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:
+   
+  kermit telnet:xyzcorp.com                            ; Opens a Telnet session
+  kermit telnet://olga@xyzcorp.com                     ; Ditto for user olga
+  kermit ftp://olga@xyzcorp.com/public/oofa.zip        ; Downloads a file
+  kermit kermit://kermit.columbia.edu/kermit/f/READ.ME ; Ditto for IKSD
+  kermit iksd://kermit.columbia.edu/kermit/f/READ.ME   ; (This works too)
+  kermit http://www.columbia.edu/kermit/index.html     ; Grabs a web page
+  kermit https://wwws.xyzcorp.com/secret/plan.html     ; Grabs a secure web pag
+e
+
+   [ [167]Kermit Home ] [ [168]C-Kermit Home ] [ [169]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  LICENSE [ [170]Top ] [ [171]Contents ] [ [172]Next ] [ [173]Previous ]
+  
+   C-Kermit has an unusual license, but a fair and sensible one given
+   that the Kermit Project must support itself out of revenue: it's not a
+   BSD license, not GPL, not Artistic, not commercial, not shareware, not
+   freeware. It can be summed up like this: if you want C-Kermit for your
+   own use, you can download and use it without cost or license (but we'd
+   appreciate it if you would purchase the manual). But if you want to
+   sell C-Kermit or bundle it with a product or otherwise distribute it
+   in a commercial setting EXCEPT WITH AN OPEN-SOURCE OPERATING SYSTEM
+   DISTRIBUTION such as Linux, FreeBSD, NetBSD, or OpenBSD, you must
+   license it. To see the complete license, give the LICENSE command at
+   the prompt, or see the COPYING.TXT file distributed with C-Kermit 7.0
+   or later, or download it from
+   [174]ftp://kermit.columbia.edu/kermit/c-kermit/COPYING.TXT. Send
+   licensing inquiries to [175]kermit@columbia.edu.
+   
+   [ [176]Kermit Home ] [ [177]C-Kermit Home ] [ [178]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  OTHER TOPICS [ [179]Top ] [ [180]Contents ] [ [181]Next ] [ [182]Previous ]
+  
+   There's way more to C-Kermit than we've touched on here --
+   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-to-date
+   information on documentation (or updated documentation itself) visit
+   the Kermit Project website:
+   
+  [183]http://www.columbia.edu/kermit/
+
+   There you will also find [184]Kermit software packages for other
+   platforms: different Unix varieties, Windows, DOS, VMS, IBM
+   mainframes, and many others: 20+ years' worth.
+   
+   [ [185]Kermit Home ] [ [186]C-Kermit Home ] [ [187]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  DOCUMENTATION AND UPDATES [ [188]Top ] [ [189]Contents ] [ [190]Next ] [
+  [191]Previous ]
+  
+   The manual for C-Kermit is:
+   
+    1. Frank da Cruz and Christine M. Gianone, [192]Using C-Kermit,
+       Second Edition, Digital Press / Butterworth-Heinemann, Woburn, MA,
+       1997, 622 pages, ISBN 1-55558-164-1. This is a printed book. It
+       covers C-Kermit 6.0.
+    2. The C-Kermit 7.0 Supplement:
+       [193]http://www.columbia.edu/kermit/ckermit70.html
+    3. The C-Kermit 8.0 Supplement:
+       [194]http://www.columbia.edu/kermit/ckermit80.html
+       
+   The C-Kermit home page is here:
+   
+  [195]http://www.columbia.edu/kermit/ckermit.html
+
+   Visit this page to learn about new versions, Beta tests, and other
+   news; to read case studies and tutorials; to download source code,
+   install packages, and [196]prebuilt binaries for many platforms. Also
+   visit:
+   
+   [197]http://www.columbia.edu/kermit/scriptlib.html
+          The Kermit script library and tutorial
+          
+   [198]http://www.columbia.edu/kermit/newfaq.html
+          The Kermit FAQ (Frequently Asked Questions about Kermit)
+          
+   [199]http://www.columbia.edu/kermit/ckfaq.html
+          The C-Kermit FAQ (Frequently Asked Questions about C-Kermit)
+          
+   [200]http://www.columbia.edu/kermit/security.html
+          The Kermit security reference.
+          
+   [201]http://www.columbia.edu/kermit/telnet.html
+          C-Kermit Telnet client documentation.
+          
+   [202]http://www.columbia.edu/kermit/studies.html
+          Case studies.
+          
+   [203]http://www.columbia.edu/kermit/ckcbwr.html
+          General C-Kermit Hints and Tips.
+          
+   [204]http://www.columbia.edu/kermit/ckubwr.html
+          Unix C-Kermit Hints and Tips.
+          
+   [205]http://www.columbia.edu/kermit/ckvbwr.html
+          VMS C-Kermit Hints and Tips.
+          
+   [206]http://www.columbia.edu/kermit/ckuins.html
+          Unix C-Kermit Installation Instructions
+          
+   [207]http://www.columbia.edu/kermit/ckvins.html
+          VMS C-Kermit Installation Instructions
+          
+   [208]http://www.columbia.edu/kermit/support.html
+          Technical support.
+          
+   [209]http://www.columbia.edu/kermit/k95tutorial.html
+          Kermit 95 tutorial (this document).
+          
+   [210]comp.protocols.kermit.misc
+          The Kermit newsgroup (unmoderated).
+          
+   [ [211]Kermit Home ] [ [212]C-Kermit Home ] [ [213]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  FILES [ [214]Top ] [ [215]Contents ] [ [216]Next ] [ [217]Previous ]
+  
+   [218]COPYING.TXT
+          C-Kermit license.
+          
+   [219]~/.kermrc
+          Initialization file.
+          
+   [220]~/.mykermrc
+          Customization file.
+          
+   ~/.kdd
+          Kermit dialing directory (see manual).
+          
+   ~/.knd
+          Kermit network directory (see manual).
+          
+   ~/.ksd
+          Kermit services directory (see manual).
+          
+   [221]ckuins.html
+          Installation instructions for Unix.
+          
+   [222]ckcbwr.html
+          General C-Kermit bugs, hints, tips.
+          
+   [223]ckubwr.html
+          Unix-specific C-Kermit bugs, hints, tips.
+          
+   [224]ckcplm.html
+          C-Kermit program logic manual.
+          
+   [225]ckccfg.html
+          C-Kermit compile-time configuration options.
+          
+   ssh
+          (in your PATH) SSH connection helper.
+          
+   rz, sz, etc.
+          (in your PATH) external protocols for XYZmodem.
+          
+   /var/spool/locks (or whatever)
+          UUCP lockfile for dialing out (see [226]installation
+          instructions).
+          
+   [ [227]Kermit Home ] [ [228]C-Kermit Home ] [ [229]C-Kermit FAQ ]
+    ________________________________________________________________________
+  
+  AUTHORS [ [230]Top ] [ [231]Contents ] [ [232]Previous ]
+  
+     Frank da Cruz and Jeffrey E Altman
+     The Kermit Project - Columbia Univerity
+     612 West 115th Street
+     New York NY 10025-7799
+     USA
+     
+   1985-present, with contributions from hundreds of others all over the
+   world.
+     _________________________________________________________________
+   
+   
+    C-Kermit 8.0 Unix Manual Page and Tutorial /
+    [233]kermit@columbia.edu / 24 October 2002
+
+References
+
+   1. http://www.columbia.edu/kermit/
+   2. http://www.columbia.edu/
+   3. http://www.columbia.edu/kermit/ckututor.pdf
+   4. ftp://kermit.columbia.edu/kermit/test/text/ckuker.nr
+   5. http://www.columbia.edu/kermit/ckututor.html#description
+   6. http://www.columbia.edu/kermit/ckututor.html#synopsis
+   7. http://www.columbia.edu/kermit/ckututor.html#options
+   8. http://www.columbia.edu/kermit/ckututor.html#commands
+   9. http://www.columbia.edu/kermit/ckututor.html#initfile
+  10. http://www.columbia.edu/kermit/ckututor.html#modes
+  11. http://www.columbia.edu/kermit/ckututor.html#connections
+  12. http://www.columbia.edu/kermit/ckututor.html#transfer
+  13. http://www.columbia.edu/kermit/ckututor.html#server
+  14. http://www.columbia.edu/kermit/ckututor.html#ftp
+  15. http://www.columbia.edu/kermit/ckututor.html#iksd
+  16. http://www.columbia.edu/kermit/ckututor.html#security
+  17. http://www.columbia.edu/kermit/ckututor.html#personae
+  18. http://www.columbia.edu/kermit/ckututor.html#license
+  19. http://www.columbia.edu/kermit/ckututor.html#other
+  20. http://www.columbia.edu/kermit/ckututor.html#documentation
+  21. http://www.columbia.edu/kermit/ckututor.html#files
+  22. http://www.columbia.edu/kermit/ckututor.html#authors
+  23. http://www.columbia.edu/kermit/ckututor.html#top
+  24. http://www.columbia.edu/kermit/ckututor.html#contents
+  25. http://www.columbia.edu/kermit/ckututor.html#synopsis
+  26. http://www.columbia.edu/kermit/ckermit.html
+  27. http://www.columbia.edu/kermit/
+  28. http://www.columbia.edu/
+  29. ftp://ftp.isi.edu/in-notes/rfc2839.txt
+  30. ftp://ftp.isi.edu/in-notes/rfc2840.txt
+  31. http://www.columbia.edu/kermit/ckututor.html#documentation
+  32. http://www.columbia.edu/kermit/
+  33. http://www.columbia.edu/kermit/
+  34. http://www.columbia.edu/kermit/ckermit.html
+  35. http://www.columbia.edu/kermit/ckfaq.html
+  36. http://www.columbia.edu/kermit/ckututor.html#top
+  37. http://www.columbia.edu/kermit/ckututor.html#contents
+  38. http://www.columbia.edu/kermit/ckututor.html#options
+  39. http://www.columbia.edu/kermit/ckututor.html#synopsis
+  40. http://www.columbia.edu/kermit/ckututor.html#kerbang
+  41. http://www.columbia.edu/kermit/ckututor.html#personae
+  42. http://www.columbia.edu/kermit/ckututor.html#kerbang
+  43. http://www.columbia.edu/kermit/ckututor.html#initfile
+  44. http://www.columbia.edu/kermit/ckututor.html#initfile
+  45. http://www.columbia.edu/kermit/ckututor.html#personae
+  46. http://www.columbia.edu/kermit/ckututor.html#options
+  47. http://www.columbia.edu/kermit/ckututor.html#commands
+  48. http://www.columbia.edu/kermit/
+  49. http://www.columbia.edu/kermit/ckermit.html
+  50. http://www.columbia.edu/kermit/ckfaq.html
+  51. http://www.columbia.edu/kermit/ckututor.html#top
+  52. http://www.columbia.edu/kermit/ckututor.html#contents
+  53. http://www.columbia.edu/kermit/ckututor.html#commands
+  54. http://www.columbia.edu/kermit/ckututor.html#description
+  55. http://www.columbia.edu/kermit/ckututor.html#commands
+  56. http://www.columbia.edu/kermit/ckututor.html#personae
+  57. http://www.columbia.edu/kermit/ckututor.html#personae
+  58. http://www.columbia.edu/kermit/ckututor.html#iksd
+  59. http://www.columbia.edu/kermit/ckututor.html#transfer
+  60. http://www.columbia.edu/kermit/ckututor.html#top
+  61. http://www.columbia.edu/kermit/ckututor.html#contents
+  62. http://www.columbia.edu/kermit/ckututor.html#initfile
+  63. http://www.columbia.edu/kermit/ckututor.html#options
+  64. http://www.columbia.edu/kermit/ckututor.html#kerbang
+  65. http://www.columbia.edu/kermit/ckututor.html#cmdlist
+  66. http://www.columbia.edu/kermit/ckututor.html#documentation
+  67. http://www.columbia.edu/kermit/ckututor.html#initfile
+  68. http://www.columbia.edu/kermit/ckututor.html#documentation
+  69. http://www.columbia.edu/kermit/ckscripts.html
+  70. http://www.columbia.edu/kermit/ckututor.html#documentation
+  71. http://www.columbia.edu/kermit/
+  72. http://www.columbia.edu/kermit/ckermit.html
+  73. http://www.columbia.edu/kermit/ckfaq.html
+  74. http://www.columbia.edu/kermit/ckututor.html#top
+  75. http://www.columbia.edu/kermit/ckututor.html#contents
+  76. http://www.columbia.edu/kermit/ckututor.html#modes
+  77. http://www.columbia.edu/kermit/ckututor.html#commands
+  78. http://www.columbia.edu/kermit/
+  79. http://www.columbia.edu/kermit/ckermit.html
+  80. http://www.columbia.edu/kermit/ckfaq.html
+  81. http://www.columbia.edu/kermit/ckututor.html#top
+  82. http://www.columbia.edu/kermit/ckututor.html#contents
+  83. http://www.columbia.edu/kermit/ckututor.html#connections
+  84. http://www.columbia.edu/kermit/ckututor.html#initfile
+  85. http://www.columbia.edu/kermit/ckfaq.html#term
+  86. http://www.columbia.edu/kermit/
+  87. http://www.columbia.edu/kermit/ckermit.html
+  88. http://www.columbia.edu/kermit/ckfaq.html
+  89. http://www.columbia.edu/kermit/ckututor.html#top
+  90. http://www.columbia.edu/kermit/ckututor.html#contents
+  91. http://www.columbia.edu/kermit/ckututor.html#transfer
+  92. http://www.columbia.edu/kermit/ckututor.html#modes
+  93. http://www.columbia.edu/kermit/ckututor.html#iksd
+  94. ftp://ftp.isi.edu/in-notes/rfc2217.txt
+  95. http://www.columbia.edu/kermit/ckututor.html#ftp
+  96. http://www.columbia.edu/kermit/
+  97. http://www.columbia.edu/kermit/ckermit.html
+  98. http://www.columbia.edu/kermit/ckfaq.html
+  99. http://www.columbia.edu/kermit/ckututor.html#top
+ 100. http://www.columbia.edu/kermit/ckututor.html#contents
+ 101. http://www.columbia.edu/kermit/ckututor.html#server
+ 102. http://www.columbia.edu/kermit/ckututor.html#connections
+ 103. http://www.columbia.edu/kermit/ckututor.html#download
+ 104. http://www.columbia.edu/kermit/ckututor.html#upload
+ 105. http://www.columbia.edu/kermit/ckututor.html#oldfashioned
+ 106. http://www.columbia.edu/kermit/ckututor.html#trouble
+ 107. http://www.columbia.edu/kermit/ckututor.html#advanced
+ 108. http://www.columbia.edu/kermit/ckututor.html#nonkermit
+ 109. http://www.columbia.edu/kermit/kermit.html#notslow
+ 110. http://www.columbia.edu/kermit/ckermit.html
+ 111. http://www.columbia.edu/kermit/k95.html
+ 112. http://www.columbia.edu/kermit/k95.html
+ 113. http://www.columbia.edu/kermit/ckermit.html
+ 114. http://www.columbia.edu/kermit/mskermit.html
+ 115. http://www.columbia.edu/kermit/
+ 116. http://www.columbia.edu/kermit/support.html
+ 117. http://www.columbia.edu/kermit/ckmanual.html
+ 118. mailto:kermit-support@columbia.edu
+ 119. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 120. http://www.columbia.edu/kermit/ckututor.html#ftp
+ 121. http://www.columbia.edu/kermit/
+ 122. http://www.columbia.edu/kermit/ckermit.html
+ 123. http://www.columbia.edu/kermit/ckfaq.html
+ 124. http://www.columbia.edu/kermit/ckututor.html#top
+ 125. http://www.columbia.edu/kermit/ckututor.html#contents
+ 126. http://www.columbia.edu/kermit/ckututor.html#ftp
+ 127. http://www.columbia.edu/kermit/ckututor.html#transfer
+ 128. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 129. http://www.columbia.edu/kermit/
+ 130. http://www.columbia.edu/kermit/ckermit.html
+ 131. http://www.columbia.edu/kermit/ckfaq.html
+ 132. http://www.columbia.edu/kermit/ckututor.html#top
+ 133. http://www.columbia.edu/kermit/ckututor.html#contents
+ 134. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 135. http://www.columbia.edu/kermit/ckututor.html#transfer
+ 136. http://www.columbia.edu/kermit/ckututor.html#server
+ 137. http://www.columbia.edu/kermit/ftpclient.html
+ 138. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 139. http://www.columbia.edu/kermit/
+ 140. http://www.columbia.edu/kermit/ckermit.html
+ 141. http://www.columbia.edu/kermit/ckfaq.html
+ 142. http://www.columbia.edu/kermit/ckermit3.html#x3
+ 143. http://www.columbia.edu/kermit/ckermit3.html#x2.2
+ 144. http://www.columbia.edu/kermit/ckututor.html#top
+ 145. http://www.columbia.edu/kermit/ckututor.html#contents
+ 146. http://www.columbia.edu/kermit/ckututor.html#security
+ 147. http://www.columbia.edu/kermit/ckututor.html#ftp
+ 148. http://www.columbia.edu/kermit/cuiksd.html
+ 149. http://www.columbia.edu/kermit/iksd.html
+ 150. http://www.columbia.edu/kermit/
+ 151. http://www.columbia.edu/kermit/ckermit.html
+ 152. http://www.columbia.edu/kermit/ckfaq.html
+ 153. http://www.columbia.edu/kermit/ckututor.html#top
+ 154. http://www.columbia.edu/kermit/ckututor.html#contents
+ 155. http://www.columbia.edu/kermit/ckututor.html#personae
+ 156. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 157. http://www.columbia.edu/kermit/security.html
+ 158. http://www.columbia.edu/kermit/
+ 159. http://www.columbia.edu/kermit/ckermit.html
+ 160. http://www.columbia.edu/kermit/ckfaq.html
+ 161. http://www.columbia.edu/kermit/ckututor.html#top
+ 162. http://www.columbia.edu/kermit/ckututor.html#contents
+ 163. http://www.columbia.edu/kermit/ckututor.html#license
+ 164. http://www.columbia.edu/kermit/ckututor.html#iksd
+ 165. http://www.columbia.edu/kermit/ckututor.html#options
+ 166. http://www.columbia.edu/kermit/ckermit3.html#x3.1.2
+ 167. http://www.columbia.edu/kermit/
+ 168. http://www.columbia.edu/kermit/ckermit.html
+ 169. http://www.columbia.edu/kermit/ckfaq.html
+ 170. http://www.columbia.edu/kermit/ckututor.html#top
+ 171. http://www.columbia.edu/kermit/ckututor.html#contents
+ 172. http://www.columbia.edu/kermit/ckututor.html#other
+ 173. http://www.columbia.edu/kermit/ckututor.html#personae
+ 174. ftp://kermit.columbia.edu/kermit/c-kermit/COPYING.TXT
+ 175. mailto:kermit@columbia.edu
+ 176. http://www.columbia.edu/kermit/
+ 177. http://www.columbia.edu/kermit/ckermit.html
+ 178. http://www.columbia.edu/kermit/ckfaq.html
+ 179. http://www.columbia.edu/kermit/ckututor.html#top
+ 180. http://www.columbia.edu/kermit/ckututor.html#contents
+ 181. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 182. http://www.columbia.edu/kermit/ckututor.html#license
+ 183. http://www.columbia.edu/kermit/
+ 184. http://www.columbia.edu/kermit/howtoget.html
+ 185. http://www.columbia.edu/kermit/
+ 186. http://www.columbia.edu/kermit/ckermit.html
+ 187. http://www.columbia.edu/kermit/ckfaq.html
+ 188. http://www.columbia.edu/kermit/ckututor.html#top
+ 189. http://www.columbia.edu/kermit/ckututor.html#contents
+ 190. http://www.columbia.edu/kermit/ckututor.html#files
+ 191. http://www.columbia.edu/kermit/ckututor.html#other
+ 192. http://www.columbia.edu/kermit/ckmanual.html
+ 193. http://www.columbia.edu/kermit/ckermit70.html
+ 194. http://www.columbia.edu/kermit/ckermit80.html
+ 195. http://www.columbia.edu/kermit/ckermit.html
+ 196. http://www.columbia.edu/kermit/ck80binaries.html
+ 197. http://www.columbia.edu/kermit/scriptlib.html
+ 198. http://www.columbia.edu/kermit/newfaq.html
+ 199. http://www.columbia.edu/kermit/ckfaq.html
+ 200. http://www.columbia.edu/kermit/security.html
+ 201. http://www.columbia.edu/kermit/telnet.html
+ 202. http://www.columbia.edu/kermit/studies.html
+ 203. http://www.columbia.edu/kermit/ckcbwr.html
+ 204. http://www.columbia.edu/kermit/ckubwr.html
+ 205. http://www.columbia.edu/kermit/ckvbwr.html
+ 206. http://www.columbia.edu/kermit/ckuins.html
+ 207. http://www.columbia.edu/kermit/ckvins.html
+ 208. http://www.columbia.edu/kermit/support.html
+ 209. http://www.columbia.edu/kermit/k95tutorial.html
+ 210. news:comp.protocols.kermit.misc
+ 211. http://www.columbia.edu/kermit/
+ 212. http://www.columbia.edu/kermit/ckermit.html
+ 213. http://www.columbia.edu/kermit/ckfaq.html
+ 214. http://www.columbia.edu/kermit/ckututor.html#top
+ 215. http://www.columbia.edu/kermit/ckututor.html#contents
+ 216. http://www.columbia.edu/kermit/ckututor.html#authors
+ 217. http://www.columbia.edu/kermit/ckututor.html#documentation
+ 218. ftp://kermit.columbia.edu/kermit/c-kermit/COPYING.TXT
+ 219. ftp://kermit.columbia.edu/kermit/c-kermit/ckermit.ini
+ 220. ftp://kermit.columbia.edu/kermit/c-kermit/ckermod.ini
+ 221. http://www.columbia.edu/kermit/ckuins.html
+ 222. http://www.columbia.edu/kermit/ckcbwr.html
+ 223. http://www.columbia.edu/kermit/ckubwr.html
+ 224. http://www.columbia.edu/kermit/ckcplm.html
+ 225. http://www.columbia.edu/kermit/ckccfg.html
+ 226. http://www.columbia.edu/kermit/ckuins.html
+ 227. http://www.columbia.edu/kermit/
+ 228. http://www.columbia.edu/kermit/ckermit.html
+ 229. http://www.columbia.edu/kermit/ckfaq.html
+ 230. http://www.columbia.edu/kermit/ckututor.html#top
+ 231. http://www.columbia.edu/kermit/ckututor.html#contents
+ 232. http://www.columbia.edu/kermit/ckututor.html#files
+ 233. mailto:kermit@columbia.edu
diff --git a/ckermit-8.0.211/ckuus2.c b/ckermit-8.0.211/ckuus2.c
new file mode 100644
index 0000000..1290763
--- /dev/null
+++ b/ckermit-8.0.211/ckuus2.c
@@ -0,0 +1,13838 @@
+#ifdef SSHTEST
+#define SSHBUILTIN
+#endif /* SSHTEST */
+
+/*  C K U U S 2  --  User interface strings & help text module for C-Kermit  */
+
+/*
+  Authors:
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    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 module contains HELP command and other long text strings.
+
+  IMPORTANT: Character string constants longer than about 250 are not portable.
+  Longer strings should be broken up into arrays of strings and accessed with
+  hmsga() rather than hmsg().
+*/
+#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 <windows.h>
+#else /* not NT */
+#define INCL_KBD
+#ifdef OS2MOUSE
+#define INCL_MOU
+#endif /* OS2MOUSE */
+#define INCL_DOSMISC
+#define INCL_DOSDEVICES
+#include <os2.h>                /* This pulls in a whole load of stuff */
+#undef COMMENT
+#endif /* NT */
+#include "ckocon.h"
+#include "ckokvb.h"
+#include "ckokey.h"
+#endif /* OS2 */
+
+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 Kermit Command screen.",
+"  Type LICENSE to see the Kermit 95 license.",
+#else
+"  Type INTRO   for a brief introduction to C-Kermit.",
+"  Type LICENSE to see the C-Kermit license.",
+#endif /* OS2 */
+"  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
+#ifdef OS2
+"  Type MANUAL  to access the K95 manual.",
+#else
+"  Type MANUAL  to access the C-Kermit manual.",
+#endif /* OS2 */
+#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.  To order,",
+"call +1 212 854-3703 or +1 800 366-2665.",
+#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.columbia.edu/kermit/ckermit.html.",
+#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
+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 / Butterworth-Heinemann 1997, ISBN 1-55558-164-1.",
+"To order: +1 212 854-3703 or +1 800 366-2665.  More info at the Kermit",
+
+"Project website, http://www.columbia.edu/kermit/.",
+""
+};
+#endif /* NOIKSD */
+
+#ifndef NOHELP
+char *newstxt[] = {
+#ifdef OS2
+"Welcome to Kermit 95 2.1.3.  Major new features include:",
+#else
+"Welcome to C-Kermit 8.0.206.  Major new features include:",
+#endif /* OS2 */
+#ifdef NT
+#ifdef KUI
+" . Runs in GUI window",
+#else
+" . GUI version available",
+#endif /* KUI */
+#endif /* NT */
+#ifdef SSHBUILTIN
+" . New built-in SSH v1 and v2 clients",
+#endif /* SSHBUILTIN */
+#ifdef NEWFTP
+" . A new built-in FTP client",
+#endif /* NEWFTP */
+#ifndef NOHTTP
+" . A new HTTP 1.1 client",
+#endif /* NOHTTP */
+#ifdef TN_COMPORT
+" . Telnet Com Port Option for dialing from Telnet modem servers",
+#endif /* TN_COMPORT */
+" . File scanning for automatic text/binary determination",
+#ifdef CKLEARN
+#ifndef OS2
+" . Learned scripts",
+#endif /* OS2 */
+#endif /* CKLEARN */
+#ifndef NOSPL
+#ifndef NOSEXP
+" . LISP-like S-Expressions and natural floating-point arithmetic",
+#endif /* NOSEXP */
+" . Lots of script programming improvements",
+#endif /* NOSPL */
+" . Performance improvements and bug fixes",
+" ",
+"Documentation:",
+" 1. \"Using C-Kermit\", second edition (1997), current with C-Kermit 6.0.",
+" 2. http://www.columbia.edu/kermit/ckermit70.html",
+"    which documents the new features of C-Kermit 7.0.",
+" 3. http://www.columbia.edu/kermit/ckermit80.html",
+"    which documents the new features of C-Kermit 8.0.",
+" ",
+"If the release date shown by the VERSION command is long past, be sure to",
+"check with the Kermit Project to see if there have been updates.",
+""
+};
+#endif /* NOHELP */
+
+#ifndef NOHELP
+char *introtxt[] = {
+#ifdef OS2
+"Welcome to K-95, Kermit communications software for:",
+#else
+#ifdef UNIX
+#ifdef HPUX
+"Welcome to HP-UX C-Kermit communications software for:",
+#else
+"Welcome to UNIX C-Kermit communications software for:",
+#endif /* HPUX */
+#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 v1 and 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 */
+
+" . ?            (question mark) Display a menu for the current command field."
+,
+" . ESC          (or TAB) 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 */
+" ",
+#ifdef OS2
+"For a Kermit 95 tutorial, visit:",
+"  http://www.columbia.edu/kermit/k95tutor.html",
+" ",
+#endif /* OS2 */
+"For a C-Kermit tutorial, visit:",
+"  http://www.columbia.edu/kermit/ckututor.html",
+" ",
+"To learn about script programming and automation:",
+"  Read the manual, \"Using C-Kermit\".  For a brief tutorial, visit:",
+"  http://www.columbia.edu/kermit/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, contact:",
+" ",
+"  The Kermit Project         E-mail: kermit@columbia.edu",
+"  Columbia University        Web:    http://www.columbia.edu/kermit/",
+"  612 West 115th Street      Voice:  +1 (212) 854-3703",
+"  New York NY  10025-7799    Fax:    +1 (212) 662-6442",
+"  USA",
+""
+};
+
+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.",
+""
+};
+
+#ifdef OS2
+#ifdef KUI
+static char * hmxygui[] = {
+"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 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 WINDOW POSITION x y",
+"  Moves the K95 window to the given X,Y coordinates, pixels from top left.",
+"  (Not yet implemented -- use command-line options to do this.)",
+" ",
+"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 */
+
+#ifdef ANYSSH
+static char * hmxxssh[] = {
+#ifdef SSHBUILTIN
+"Syntax: SSH { ADD, AGENT, CLEAR, KEY, [ OPEN ], V2 } operands...",
+"  Performs an SSH-related action, depending on the keyword that follows:",
+" ",
+"SSH ADD LOCAL-PORT-FORWARD local-port host port",
+"  Adds a port forwarding triplet to the local port forwarding list.",
+"  The triplet specifies a local port to be forwarded and the hostname /",
+"  ip-address and port number to which the port should be forwarded from",
+"  the remote host.  Port forwarding is activated at connection",
+"  establishment and continues until the connection is terminated.",
+" ",
+"SSH ADD REMOTE-PORT-FORWARD remote-port host port",
+"  Adds a port forwarding triplet to the remote port forwarding list.",
+"  The triplet specifies a remote port to be forwarded and the",
+"  hostname/ip-address and port number to which the port should be",
+"  forwarded from the local machine.  Port forwarding is activated at",
+"  connection establishment and continues until the connection is",
+"  terminated.",
+" ",
+"SSH AGENT ADD [ identity-file ]",
+"  Adds the contents of the identity-file (if any) to the SSH AGENT",
+"  private key cache.  If no identity-file is specified, all files",
+"  specified with SET SSH IDENTITY-FILE are added to the cache.",
+" ",
+"SSH AGENT DELETE [ identity-file ]",
+"  Deletes the contents of the identity-file (if any) from the SSH AGENT",
+"  private key cache.  If no identity-file is specified, all files",
+"  specified with SET SSH IDENTITY-FILE are deleted from the cache.",
+" ",
+"SSH AGENT LIST [ /FINGERPRINT ]",
+"  Lists the contents of the SSH AGENT private key cache.  If /FINGERPRINT",
+"  is specified, the fingerprint of the private keys are displayed instead",
+"  of the keys.",
+" ",
+"SSH CLEAR LOCAL-PORT-FORWARD",
+"  Clears the local port forwarding list.",
+" ",
+"SSH CLEAR REMOTE-PORT-FORWARD",
+"  Clears the remote port forwarding list.",
+" ",
+"SSH KEY commands:",
+"  The SSH KEY commands create and manage public and private key pairs",
+"  (identities).  There are three forms of SSH keys.  Each key pair is",
+"  stored in its own set of files:",
+" ",
+"   Key Type      Private Key File           Public Key File",
+"    v1 RSA keys   \\v(appdata)ssh/identity   \\v(appdata)ssh/identity.pub",
+"    v2 RSA keys   \\v(appdata)ssh/id_rsa     \\v(appdata)ssh/id_rsa.pub",
+"    v2 DSA keys   \\v(appdata)ssh/id_dsa     \\v(appdata)ssh/id_dsa.pub",
+" ",
+"  Keys are stored using the OpenSSH keyfile format.  The private key",
+"  files can be (optionally) protected by specifying a passphrase.  A",
+"  passphrase is a longer version of a password.  English text provides",
+"  no more than 2 bits of key data per character.  56-bit keys can be",
+"  broken by a brute force attack in approximately 24 hours.  When used,",
+"  private key files should therefore be protected by a passphrase of at",
+"  least 40 characters (about 80 bits).",
+" ",
+"  To install a public key file on the host, you must transfer the file",
+"  to the host and append it to your \"authorized_keys\" file.  The file",
+"  permissions must be 600 (or equivalent).",
+" ",
+"SSH KEY CHANGE-PASSPHRASE [ /NEW-PASSPHRASE:passphrase",
+"      /OLD-PASSPHRASE:passphrase ] filename",
+"  This re-encrypts the specified private key file with a new passphrase.",
+"  The old passphrase is required.  If the passphrases (and filename) are",
+"  not provided Kermit prompts your for them.",
+" ",
+"SSH KEY CREATE [ /BITS:bits /PASSPHRASE:passphrase",
+"    /TYPE:{ V1-RSA, V2-DSA, V2-RSA } /V1-RSA-COMMENT:comment ] filename",
+"  This command creates a new private/public key pair.  The defaults are:",
+"  BITS:1024 and TYPE:V2-RSA.  The filename is the name of the private",
+"  key file.  The public key is created with the same name with .pub",
+"  appended to it.  If a filename is not specified Kermit prompts you for",
+"  it.  V1 RSA key files may have an optional comment, which is ignored",
+"  for other key types.",
+" ",
+"SSH KEY DISPLAY [ /FORMAT:{FINGERPRINT,IETF,OPENSSH,SSH.COM} ] filename",
+"  This command displays the contents of a public or private key file.",
+"  The default format is OPENSSH.",
+" ",
+"SSH KEY V1 SET-COMMENT filename comment",
+"  This command replaces the comment associated with a V1 RSA key file.",
+" ",
+"SSH [ OPEN ] host [ port ] [ /COMMAND:command /USER:username",
+"      /PASSWORD:pwd /VERSION:{ 1, 2 } /X11-FORWARDING:{ ON, OFF } ]",
+"  This command establishes a new connection using SSH version 1 or",
+"  version 2 protocol.  The connection is made to the specified host on",
+"  the SSH port (you can override the port by including a port name or",
+"  number after the host name).  Once the connection is established the",
+"  authentication negotiations begin.  If the authentication is accepted,",
+"  the local and remote port forwarding lists are used to establish the",
+"  desired connections.  If X11 Forwarding is active, this results in a",
+"  remote port forwarding between the X11 clients on the remote host and",
+"  X11 Server on the local machine.  If a /COMMAND is provided, the",
+"  command is executed on the remote host in place of your default shell.",
+" ",
+"  An example of a /COMMAND to execute C-Kermit in SERVER mode is:",
+"     SSH OPEN hostname /COMMAND:{kermit -x -l 0}",
+" ",
+"SSH V2 REKEY",
+"  Requests that an existing SSH V2 connection generate new session keys.",
+#else  /* SSHBUILTIN */
+"Syntax: SSH [ options ] <hostname> [ 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
+"SET SSH AGENT-FORWARDING { ON, OFF }",
+"  If an authentication agent is in use, setting this value to ON",
+"  results in the connection to the agent being forwarded to the remote",
+"  computer.  The default is OFF.",
+" ",
+"SET SSH CHECK-HOST-IP { ON, OFF }",
+"  Specifies whether the remote host's ip-address should be checked",
+"  against the matching host key in the known_hosts file.  This can be",
+"  used to determine if the host key changed as a result of DNS spoofing.",
+"  The default is ON.",
+" ",
+"SET SSH COMPRESSION { ON, OFF }",
+"  Specifies whether compression will be used.  The default is ON.",
+" ",
+"SET SSH DYNAMIC-FORWARDING { ON, OFF }",
+"  Specifies whether Kermit is to act as a SOCKS4 service on port 1080",
+"  when connected to a remote host via SSH.  When Kermit acts as a SOCKS4",
+"  service, it accepts connection requests and forwards the connections",
+"  through the remote host.  The default is OFF.",
+" ",
+"SET SSH GATEWAY-PORTS { ON, OFF }",
+"  Specifies whether Kermit should act as a gateway for forwarded",
+"  connections received from the remote host.  The default is OFF.",
+" ",
+"SET SSH GSSAPI DELEGATE-CREDENTIALS { ON, OFF }",
+"  Specifies whether Kermit should delegate GSSAPI credentials to ",
+"  the remote host after authentication.  Delegating credentials allows",
+"  the credentials to be used from the remote host.  The default is OFF.",
+" ",
+"SET SSH HEARTBEAT-INTERVAL <seconds>",
+"  Specifies a number of seconds of idle time after which an IGNORE",
+"  message will be sent to the server.  This pulse is useful for",
+"  maintaining connections through HTTP Proxy servers and Network",
+"  Address Translators.  The default is OFF (0 seconds).",
+" ",
+"SET SSH IDENTITY-FILE filename [ filename [ ... ] ]",
+"  Specifies one or more files from which the user's authorization",
+"  identities (private keys) are to be read when using public key",
+"  authorization.  These are files used in addition to the default files:",
+" ",
+"    \\v(appdata)ssh/identity      V1 RSA",
+"    \\v(appdata)ssh/id_rsa        V2 RSA",
+"    \\v(appdata)ssh/id_dsa        V2 DSA",
+" ",
+"SET SSH KERBEROS4 TGT-PASSING { ON, OFF }",
+"  Specifies whether Kermit should forward Kerberos 4 TGTs to the host.",
+"  The default is OFF.",
+" ",
+"SET SSH KERBEROS5 TGT-PASSING { ON, OFF }",
+"  Specifies whether Kermit should forward Kerberos 5 TGTs to to the",
+"  host.  The default is OFF.",
+" ",
+"SET SSH PRIVILEGED-PORT { ON, OFF }",
+"  Specifies whether a privileged port (less than 1024) should be used",
+"  when connecting to the host.  Privileged ports are not required except",
+"  when using SSH V1 with Rhosts or RhostsRSA authorization.  The default",
+"  is OFF.",
+" ",
+"SET SSH QUIET { ON, OFF }",
+"  Specifies whether all messages generated in conjunction with SSH",
+"  protocols should be suppressed.  The default is OFF.",
+" ",
+"SET SSH STRICT-HOST-KEY-CHECK { ASK, ON, OFF }",
+"  Specifies how Kermit should behave if the the host key check fails.",
+"  When strict host key checking is OFF, the new host key is added to the",
+"  protocol-version-specific user-known-hosts-file.  When strict host key",
+"  checking is ON, the new host key is refused and the connection is",
+"  dropped.  When set to ASK, Kermit prompt you to say whether the new",
+"  host key should be accepted.  The default is ASK.",
+" ",
+"  Strict host key checking protects you against Trojan horse attacks.",
+"  It depends on you to maintain the contents of the known-hosts-file",
+"  with current and trusted host keys.",
+" ",
+"SET SSH USE-OPENSSH-CONFIG { ON, OFF }",
+"  Specifies whether Kermit should parse an OpenSSH configuration file",
+"  after applying Kermit's SET SSH commands.  The configuration file",
+"  would be located at \\v(home)ssh/ssh_config.  The default is OFF.",
+" ",
+"SET SSH V1 CIPHER { 3DES, BLOWFISH, DES }",
+"  Specifies which cipher should be used to protect SSH version 1",
+"  connections.  The default is 3DES.",
+" ",
+"SET SSH V1 GLOBAL-KNOWN-HOSTS-FILE filename",
+"  Specifies the location of the system-wide known-hosts file.  The",
+"  default is:",
+" ",
+"    \v(common)ssh_known_hosts",
+" ",
+"SET SSH V1 USER-KNOWN-HOSTS-FILE filename",
+"  Specifies the location of the user-known-hosts-file.  The default",
+"  location is:",
+" ",
+"    \\v(appdata)ssh/known_hosts",
+" ",
+"SET SSH V2 AUTHENTICATION { EXTERNAL-KEYX, GSSAPI, HOSTBASED, ",
+"    KEYBOARD-INTERACTIVE, PASSWORD, PUBKEY, SRP-GEX-SHA1 } [ ... ]",
+"  Specifies an ordered list of SSH version 2 authentication methods to",
+"  be used when connecting to the remote host.  The default list is:",
+" ",
+"    external-keyx gssapi hostbased publickey srp-gex-sha1 publickey",
+"    keyboard-interactive password none",
+" ",
+"SET SSH V2 AUTO-REKEY { ON, OFF }",
+"  Specifies whether Kermit automatically issues rekeying requests",
+"  once an hour when SSH version 2 in in use.  The default is ON.",
+" ",
+"SET SSH V2 CIPHERS { 3DES-CBC, AES128-CBC AES192-CBC AES256-CBC",
+"     ARCFOUR BLOWFISH-CBC CAST128-CBC RIJNDAEL128-CBC RIJNDAEL192-CBC",
+"     RIJNDAEL256-CBC }",
+"  Specifies an ordered list of SSH version ciphers to be used to encrypt",
+"  the established connection.  The default list is:",
+" ",
+"    aes128-cbc 3des-cbc blowfish-cbc cast128-cbc arcfour aes192-cbc",
+"    aes256-cbc",
+" ",
+"  \"rijndael\" is an alias for \"aes\".",
+" ",
+"SET SSH V2 GLOBAL-KNOWN-HOSTS-FILE filename",
+"  Specifies the location of the system-wide known-hosts file.  The default",
+"  location is:",
+" ",
+"    \\v(common)ssh/known_hosts2",
+" ",
+"SET SSH V2 HOSTKEY-ALGORITHMS { SSH-DSS, SSH-RSA }",
+"  Specifies an ordered list of hostkey algorithms to be used to verify",
+"  the identity of the host.  The default list is",
+" ",
+"    ssh-rsa ssh-dss",
+" ",
+"SET SSH V2 MACS { HMAC-MD5 HMAC-MD5-96 HMAC-RIPEMD160 HMAC-SHA1",
+"     HMAC-SHA1-96 }",
+"  Specifies an ordered list of Message Authentication Code algorithms to",
+"  be used for integrity  protection of the established connection.  The",
+"  default list is:",
+" ",
+"    hmac-md5 hmac-sha1 hmac-ripemd160 hmac-sha1-96 hmac-md5-96",
+" ",
+"SET SSH V2 USER-KNOWN-HOSTS-FILE filename",
+"  Specifies the location of the user-known-hosts file.  The default",
+"  location is:",
+" ",
+"    \\v(appdata)ssh/known_hosts2",
+" ",
+"SET SSH VERBOSE level",
+"  Specifies how many messages should be generated by the OpenSSH engine.",
+"  The level can range from 0 to 7.  The default value is 2.",
+" ",
+"SET SSH VERSION { 1, 2, AUTOMATIC }",
+"  Specifies which SSH version should be negotiated.  The default is",
+"  AUTOMATIC which means use version 2 if supported; otherwise to fall",
+"  back to version 1.",
+" ",
+"SET SSH X11-FORWARDING { ON, OFF }",
+"  Specifies whether X Windows System Data is to be forwarded across the",
+"  established SSH connection.  The default is OFF.  When ON, the DISPLAY",
+"  value is either set using the SET TELNET ENV DISPLAY command or read",
+"  from the DISPLAY environment variable.",
+" ",
+"SET SSH XAUTH-LOCATION filename",
+"  Specifies the location of the xauth executable (if provided with the",
+"  X11 Server software.)",
+#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 */
+
+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[] = {
+#ifdef OS2
+"Firewall Traversal in Kermit 95",
+#else
+"Firewall Traversal in C-Kermit",
+#endif
+" ",
+#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] [<hostname or ip-address>[:<port>]]",
+"  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:<agent> /USER:<user> /PASSWORD:<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 */
+
+"Kermit/2 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.",
+" ",
+"Kermit/2 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.",
+
+" ",
+
+"Kermit/2 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[] = {
+"\\fword(s1,n1,s2,s3,n2,n3) - Extract word from string.",
+"    s1 = source string",
+"    n1 = word number (1-based)",
+"    s2 = optional break set.",
+"    s3 = optional include set.",
+"    n2 = optional grouping mask.",
+"    n3 = optional separator flag:",
+"       0 = collapse adjacent separators",
+"       1 = don't collapse adjacent separators.",
+" ",
+"  Default break set is all characters except ASCII letters and digits.",
+"  ASCII (C0) control characters are always treated as break characters.",
+"  Default include set is null.",
+" ",
+"  If grouping mask given and 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:  <a b c>",
+" ",
+"  Nesting is possible with {}()[]<> but not with quotes or apostrophes.",
+" ",
+"Returns string:",
+"  Word number n, if there is one, otherwise an empty string.",
+""
+};
+
+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 [ /NOMATCH ] { number-of-seconds, time-of-day } [ text ]",
+"Example: INPUT 5 Login:  or  INPUT 23:59:59 RING",
+"  Waits up to the given number of seconds, or until the given time of day,",
+"  for the given text to arrive on the connection.  If no text is given,",
+"  INPUT waits for any character.  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.",
+"  For use in script programs with IF FAILURE and IF SUCCESS.  Also see",
+"  MINPUT, REINPUT, SET INPUT.  See HELP PAUSE for details on time-of-day",
+"  format.  The text, if given, can be a \\pattern() invocation, in which",
+"  case it is treated as a pattern rather than a literal string (HELP",
+"  PATTERNS for details).",
+""};
+
+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.",
+"" };
+#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 <number>",
+"  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 <number>",
+"  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 <number>",
+"  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 \"%\" 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",
+"  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 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 contained any lines that match the pattern, otherwise it fails.",
+#ifdef UNIXOROSK
+"  Synonym: FIND.",
+#else
+"  Synonym: GREP.",
+#endif /* UNIXOROSK */
+" ",
+"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 (ASCII only) when comparing.",
+"  /NOMATCH",
+"    Searches for lines that do NOT match the pattern.",
+" ",
+"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.",
+"  /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.",
+"  /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.",
+""};
+
+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.",
+#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.",
+"   /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.",
+"   /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.",
+#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 */
+""};
+
+
+#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 95 application data directory",
+"    common        Kermit 95'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)",
+" ",
+"/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 [ <switches> ] OPEN [{ /SSL, /TLS }] <hostname> <service/port>",
+#else
+"HTTP [ <switches> ] OPEN <hostname> <service/port>",
+#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 <switches> 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 [ <switches> ] CONNECT <host>[:<port>]",
+"  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 [ <switches> ] GET <remote-filename> [ <local-filename> ]",
+"  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 [ <switches> ] HEAD <remote-filename> [ <local-filename> ]",
+"  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 [ <switches> ] INDEX <remote-directory> [ <local-filename> ]",
+"  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 [ <switches> ] POST [ /MIME-TYPE:<type> ] <local-file> <remote-path>",
+"     [ <dest-file> ]",
+"  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 [ <switches> ] PUT [ /MIME-TYPE:<type> ] <local-file> <remote-file>",
+"     [ <dest-file> ]",
+"  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 [ <switches> ] DELETE <remote-filename>",
+"  Instructs the server to delete the specified filename.",
+" ",
+"where <switches> are:",
+"/AGENT:<user-agent>",
+"  Identifies the client to the server; \"C-Kermit\" or \"Kermit-95\"",
+"  by default.",
+" ",
+"/HEADER:<header-line>",
+"  Used for specifying any optional headers.  A list of headers is provided",
+"  using braces for grouping:",
+" ",
+"    /HEADER:{{<tag>:<value>}{<tag>:<value>}...}",
+" ",
+"  For a listing of valid <tag> value and <value> 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:<name>",
+"  In case a page requires a username for access.",
+" ",
+"/PASSWORD:<password>",
+"  In case a page requires a password for access.",
+" ",
+"/ARRAY:<arrayname>",
+"  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 ] } <action> [ 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:<name> /LIFETIME:<minutes> -",
+"    /PASSWORD:<password> /PREAUTH /REALM:<name> <principal> ]",
+" ",
+"  All switches are optional.  Kerberos 4 INITIALIZE switches are:",
+" ",
+"  /INSTANCE:<name>",
+"    Allows an Instance (such as a hostname) to be specified.",
+" ",
+"  /LIFETIME:<number>",
+"    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:<string>",
+"    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:<name>",
+"    Allows a realm to be specified (overriding the default realm).",
+" ",
+"  <principal>",
+"    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:<filename> ] { INITIALIZE [ switches ], DESTROY,",
+"    LIST-CREDENTIALS ...}",
+" ",
+"The INITIALIZE command for Kerberos 5 can include a number of switches;",
+"all are optional:",
+" ",
+"AUTH K5 [ /CACHE:<filename> ] INITITIALIZE [ /ADDRESSES:<addr-list>",
+"  /FORWARDABLE /KERBEROS4 /LIFETIME:<minutes> /PASSWORD:<password>",
+"  /POSTDATE:<date-time> /PROXIABLE /REALM:<name> /RENEW /RENEWABLE:<minutes>",
+"  /SERVICE:<name> /VALIDATE <principal> ]",
+" ",
+"  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:<name>",
+"    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:<number>",
+"    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:<string>",
+"    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:<date-time>",
+"    Requests a postdated ticket, valid starting at <date-time>.  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:<string>",
+"    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:<number>",
+"    Requests renewable tickets, with a total lifetime of <number> minutes.",
+" ",
+"  /SERVICE:<string>",
+"    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.",
+" ",
+"  <principal>",
+"    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 <file-character-set> <transfer-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 <xfer-character-set> <file-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, which is providing 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, and 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 [ <switches> ] <pattern> <filespec>",
+"  TYPE /MATCH:<pattern> <file>",
+"  \\farraylook(<pattern>,<arrayname>)",
+"  \\fsearch(<pattern>,<string>[,<offset>])",
+"  \\frsearch(<pattern>,<string>[,<offset>])",
+"  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 that use patterns 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, which is providing 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: 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, and z rather than a through z.",
+" ",
+#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 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 } 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.  If the timeout interval is 0 the",
+"  MINPUT command does not wait; i.e. the given text must already be",
+"  available for reading for the MINPUT command to succeed.  If the interval",
+"  is negative, the MINPUT command waits forever.",
+" ",
+"Also see: INPUT, REINPUT, SET INPUT.",
+"" };
+#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",
+"  When sending in local mode, this 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 should",
+"  normally contain variables like \\v(filename) or \\v(filenum).",
+" ",
+"/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 <keyword> 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",
+"     Specifies the title to use for the dialog box.",
+#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 */
+"  /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:",
+" ",
+"  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."
+,
+" ",
+"  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:<arrayname>",
+"  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:<text>",
+"  Specifies <text> 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 sending 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\
+  Resend the file or files, whose previous transfer was interrupted.\n\
+  Picks up from where previous transfer left off, IF the receiver was told\n\
+  to SET FILE INCOMPLETE KEEP.  Only works for binary-mode transfers.\n\
+  Requires the other Kermit to have RESEND capability.";
+
+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 [ <mode> [ <as-name> ] ]",
+"  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 [ <pattern> [ <pattern> ... ] ]",
+"  Adds the pattern(s), if any, to the SET FILE BINARY-PATTERNS list.",
+" ",
+"ADD TEXT-PATTERNS [ <pattern> [ <pattern> ... ] ]",
+"  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 [ <pattern> [ <pattern> ... ] ]",
+"  Removes the pattern(s), if any, from the SET FILE BINARY-PATTERNS list",
+" ",
+"REMOVE TEXT-PATTERNS [ <pattern> [ <pattern> ... ] ]",
+"  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 type",
+" ",
+"  Type of packet block check to be used for error detection, 1, 2, 3, or",
+"  BLANK-FREE-2.  Type 1 is standard, and catches most errors.  Types 2 and 3",
+"  specify more rigorous checking at the cost of higher overhead.  The",
+"  BLANK-FREE-2 type is the same as Type 2, but is guaranteed to contain no",
+"  blanks.",
+"" };
+
+static char * hmxydeb[] = {
+"Syntax: SET DEBUG { SESSION, ON, OFF, TIMESTAMP }",
+" ",
+"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.",
+"" };
+
+#ifdef CK_SPEED
+static char *hmxyqctl[] = {
+"Syntax: SET CONTROL-CHARACTER { PREFIXED, UNPREFIXED } { <code>..., ALL }",
+" ",
+"  <code> is the numeric ASCII code for a control character 1-31,127-159,255."
+,
+"  The word \"ALL\" means all characters in this range.",
+" ",
+"  PREFIXED <code> means the given control character must be converted to a",
+"  printable character and prefixed, the default for all control characters.",
+" ",
+"  UNPREFIXED <code> 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 <code> values in one",
+"  command, separated by spaces.",
+"" };
+#endif /* CK_SPEED */
+
+#ifndef NODIAL
+static char *hxymodm[] = {
+"Syntax: SET MODEM <parameter> <value> ...",
+" ",
+"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 <name>",
+
+" 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 <list>",
+"  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 <text>",
+"  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 <number>",
+"  Specify the maximum interface speed for the modem.",
+" ",
+"SET MODEM NAME <text>",
+"  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 <number>",
+"  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 [ <number> ]",
+"  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 <name> 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 <number>",
+"  How many times to redial each number if the dialing result is busy or no",
+"  no answer, until the call is succesfully answered.  The default is 0",
+"  because automatic redialing is illegal in some countries.",
+" ",
+"SET DIAL INTERVAL <number>",
+"  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 [ <list> ]",
+"  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 [ <text> ]",
+"  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 [ <text> ]",
+"  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 [ <text> ]",
+"  Your long-distance dialing prefix, to be used with portable dialing",
+"  directory entries that result in long-distance calls.",
+" ",
+"SET DIAL LD-SUFFIX [ <text> ]",
+"  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 [ <number> [ <number> [ ... ] ] ]",
+"  Tells Kermit the toll-free area code(s) in your country.",
+" ",
+"SET DIAL TOLL-FREE-PREFIX [ <text> ]",
+"  You toll-free dialing prefix, in case it is different from your long-",
+"  distance dialing prefix.",
+" ",
+"SET DIAL INTL-PREFIX <text>",
+"  Your international dialing prefix, to be used with portable dialing",
+"  directory entries that result in international calls.",
+" ",
+"SET DIAL INTL-SUFFIX <text>",
+"  International dialing suffix, if any, to be used with portable dialing",
+"  directory entries that result in international calls.",
+" ",
+"SET DIAL PBX-OUTSIDE-PREFIX <text>",
+"  Use this to tell Kermit how to get an outside line when dialing from a",
+"  Private Branch Exchange (PBX).",
+" ",
+"SET DIAL PBX-EXCHANGE <text> [ <text> [ ... ] ]",
+"  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 <text>",
+"  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.",
+"   APPEND - Append the incoming file to the end of the existing file.",
+"   DISCARD - Refuse and/or discard the incoming file.",
+"   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 [ <directory-name> ]",
+"  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 [ <pattern> [ <pattern> ... ] ]",
+"  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 [ <pattern> [ <pattern> ... ] ]",
+"  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 <list>.",
+" ",
+"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 and",
+"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 <command>",
+"  IF ( EXIST oofa.txt || = \\v(nday) 3 ) <command>",
+"  IF ( EXIST oofa.txt || = \\v(nday) 3 ) { <command>, <command>, ... }",
+" ",
+"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",
+"  K-95        - 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",
+"  EXIST filename                    - The named file exists",
+"  ABSOLUTE filename                 - The filename is absolute, not relative",
+#ifdef CK_TMPDIR
+"  DIRECTORY string                  - The string is the name of a directory",
+#endif /* CK_TMPDIR */
+"  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",
+" ",
+"  VERSION - equivalent to \"if >= \\v(version) ...\"",
+"  COUNT   - subtract one from COUNT, execute the command if the result is",
+"            greater than zero (see SET COUNT)",
+" ",
+"  EQUAL s1 s2 - s1 and s2 (character strings or variables) are equal",
+"  LLT s1 s2   - s1 is lexically (alphabetically) less than s2",
+"  LGT s1 s1   - s1 is lexically (alphabetically) greater than 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",
+" ",
+"  (number by itself) - fails if the number is 0, succeeds otherwise",
+" ",
+"  TRUE     - always succeeds",
+"  FALSE    - always fails",
+" ",
+"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 }",
+" ",
+"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 <variable> { 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.",
+" ",
+"Switches:",
+" /DEFAULT:text",
+"  Text to supply if the user enters a blank response or the /TIMEOUT",
+"  limit expired with no response.",
+" ",
+#ifdef OS2
+" /POPUP",
+"  The prompt and response dialog takes place in a text-mode popup.",
+"  K95 only; in C-Kermit this switch is ignored.",
+" ",
+#ifdef KUI
+" /GUI",
+"  The prompt and response dialog takes place in a GUI popup.",
+"  K95 GUI version only; in C-Kermit and the K95 console version,", 
+"  this switch is ignored.",
+" ",
+#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 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.",
+" ",
+"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: .<variable-name> <assignment-operator> <value>",
+"  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.",
+" ",
+"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 [ number ]",
+"  Decrement (subtract one from) the value of a variable if the current value",
+"  is numeric.  If the number argument is given, subtract that number",
+"  instead.",
+" ",
+"Examples: DECR \\%a, DECR \\%a 7, DECR \\%a \\%n", "" };
+
+static char *hxxinc[] = {
+"Syntax: INCREMENT variablename [ number ]",
+"  Increment (add one to) the value of a variable if the current value is",
+"  numeric.  If the number argument is given, add that number instead.",
+" ",
+"Examples: INCR \\%a, INCR \\%a 7, INCR \\%a \\%n", "" };
+#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 K95 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 K95 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:<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 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: TRANSLATE file1 cs1 cs2 [ file2 ]",
+"  Translates 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:",
+" ",
+"    TRANSLATE lasagna.lat latin1 italian lasagna.nrc",
+" ",
+"  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 } [ <what> ]",
+" ",
+"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 <time> FILE { CREATION, DELETION, MODIFICATION } <filename>",
+" ",
+"where <time> is as above, and <filename> is the name of a single file.",
+"Kermit waits up to the given amount of time for the specified event to occur",
+"with the specified file, succeeds if it does, fails if it doesn't.",
+"" };
+#endif /* NOSPL */
+
+static char *hxxwri[] = {
+"Syntax: WRITE name text",
+"  Writes the given text to the named log or file.  The text text may include",
+"  backslash codes, and is not terminated by a newline unless you include the",
+"  appropriate code.  The name parameter can be any of the following:",
+" ",
+"   DEBUG-LOG",
+"   ERROR (standard error)",
+#ifndef NOSPL
+"   FILE (the OPEN WRITE, OPEN !WRITE, or OPEN APPEND file, see HELP OPEN)",
+#endif /* NOSPL */
+"   PACKET-LOG",
+"   SCREEN (compare with ECHO)",
+#ifndef NOLOCAL
+"   SESSION-LOG",
+#endif /* NOLOCAL */
+"   TRANSACTION-LOG", "" };
+
+#ifndef NODIAL
+static char *hxxlook[] = { "Syntax: LOOKUP name",
+"  Looks up the given name in the dialing directory or directories, if any,",
+"  specified in the most recent SET DIAL DIRECTORY command.  Each matching",
+"  entry is shown, along with any transformations that would be applied to",
+"  portable-format entries based on your locale.  HELP DIAL, HELP SET DIAL",
+"  for further info.",
+""
+};
+
+static char *hxxansw[] = { "Syntax:  ANSWER [ <seconds> ]",
+#ifdef OS2
+"  Waits for a modem call to come in.  Prior SET MODEM TYPE and SET PORT",
+#else
+"  Waits for a modem call to come in.  Prior SET MODEM TYPE and SET LINE",
+#endif /* OS2 */
+"  required.  If <seconds> is 0 or not specified, Kermit waits forever or",
+"  until interrupted, otherwise Kermit waits the given number of seconds.",
+"  The ANSWER command puts the modem in autoanswer mode.  Subsequent DIAL",
+"  commands will automatically put it (back) in originate mode.  SHOW MODEM,",
+"  HELP SET MODEM for more info.",
+""
+};
+
+static char *hxxdial[] = { "Syntax:  DIAL phonenumber",
+"Example: DIAL 7654321",
+"  \
+Dials a number using an autodial modem.  First you must SET MODEM TYPE, then",
+#ifdef OS2
+"  SET PORT (or in Windows only, SET PORT TAPI instead of SET MODEM TYPE and",
+"  SET LINE), then SET SPEED. Then give the DIAL command, including the phone",
+#else
+"  SET LINE, then SET SPEED.  Then give the DIAL command, including the phone",
+#endif /* OS2 */
+"  number, for example:",
+" ",
+"   DIAL 7654321",
+#ifdef NETCONN
+" ",
+"  If the modem is on a network modem server, SET HOST first, then SET MODEM",
+"  TYPE, then DIAL.",
+#endif /* NETCONN */
+" ",
+"If you give the DIAL command interactively at the Kermit prompt, and the",
+"call is placed successfully, Kermit automatically enters CONNECT mode.",
+"If the DIAL command is given from a macro or command file, Kermit remains",
+"in command mode after the call is placed, successfully or not.  You can",
+"change this behavior with the SET DIAL CONNECT command.",
+" ",
+"If the phonenumber starts with a letter, and if you have used the SET DIAL",
+"DIRECTORY command to specify one or more dialing-directory files, Kermit",
+"looks it up in the given file(s); if it is found, the name is replaced by",
+"the number or numbers associated with the name.  If it is not found, the",
+"name is sent to the modem literally.",
+" ",
+"If the phonenumber starts with an equals sign (\"=\"), this forces the part",
+"after the = to be sent literally to the modem, even if it starts with a",
+"letter, without any directory lookup.",
+" ",
+"You can also give a list of phone numbers enclosed in braces, e.g:",
+" ",
+"  dial {{7654321}{8765432}{+1 (212 555-1212}}",
+" ",
+"(Each number is enclosed in braces and the entire list is also enclosed in",
+"braces.)  In this case, each number is tried until there is an answer.  The",
+"phone numbers in this kind of list can not be names of dialing directory",
+"entries.",
+" ",
+"A dialing directory is a plain text file, one entry per line:",
+" ",
+"  name  phonenumber  ;  comments",
+" ",
+"for example:",
+" ",
+"  work    9876543              ; This is a comment",
+"  e-mail  +1  (212) 555 4321   ; My electronic mailbox",
+"  germany +49 (511) 555 1234   ; Our branch in Hanover",
+" ",
+"If a phone number starts with +, then it must include country code and",
+"area code, and C-Kermit will try to handle these appropriately based on",
+"the current locale (HELP SET DIAL for further info); these are called",
+"PORTABLE entries.  If it does not start with +, it is dialed literally.",
+" ",
+"If more than one entry is found with the same name, Kermit dials all of",
+"them until the call is completed; if the entries are in portable format,",
+"Kermit dials them in cheap-to-expensive order: internal, then local, then",
+"long-distance, then international, based on its knowledge of your local",
+"country code and area code (see HELP SET DIAL).",
+" ",
+"Specify your dialing directory file(s) with the SET DIAL DIRECTORY command.",
+" ",
+#ifdef NETCONN
+"See also SET DIAL, SET MODEM, SET LINE, SET HOST, SET SPEED, REDIAL, and",
+"PDIAL.",
+#else
+"See also SET DIAL, SET MODEM, SET LINE, SET SPEED, PDIAL, and REDIAL.",
+#endif /* NETCONN */
+"" };
+
+#ifdef CK_TAPI
+static char *hxxtapi[] = {
+"TAPI CONFIGURE-LINE <tapi-line>",
+"  Displays the TAPI Configure Line Dialog box and allows you to",
+"  alter the default configuration for the specified <tapi-line>.",
+" ",
+"TAPI DIALING-PROPERTIES",
+"  Displays the TAPI Dialing Properties (locations) Dialog box.  The",
+"  Dialing rules may be changed and locations created and deleted.",
+"  When the dialog box is closed, K-95 imports the current Dialing",
+"  Properties' Location into the Kermit DIAL command settings.",
+""};
+
+static char *hxytapi[] = {
+"SET TAPI LINE <tapi-line>",
+"  Opens a TAPI device for use by Kermit.",
+" ",
+"SET TAPI MODEM-DIALING {ON, [OFF]}",
+"  If TAPI MODEM-DIALING is OFF when SET TAPI LINE is issued, Kermit opens",
+"  the TAPI device directly as a \"raw port\".  The device is unavailable to",
+"  other applications and Kermit performs dialing functions using its",
+"  built-in dialing and modem databases.  If TAPI MODEM-DIALING is ON, TAPI",
+"  handles all dialing functions and the port may be shared with other",
+"  applications when a call in not active.  When TAPI MODEM-DIALING is OFF,",
+"  SET MODEM TYPE TAPI Kermit uses the TAPI modem commands imported from the",
+"  Windows Registry during the previous SET TAPI LINE call.",
+" ",
+"SET TAPI LOCATION <tapi-location>",
+"  Specifies the TAPI location to make current for the entire system.  The",
+"  <tapi-location>'s dialing properties are imported into Kermit's SET DIAL",
+"  command database.",
+" ",
+"SET TAPI PHONE-NUMBER-CONVERSIONS {ON, OFF, [AUTO]}",
+"  Controls whether the phone number conversions are performed by TAPI (ON)",
+"  or by Kermit (OFF), or according the type of port that was selected",
+"  (AUTO); AUTO is the default, and is equivalent to ON if the current",
+"  LINE/PORT is a TAPI device and TAPI MODEM-DIALING is ON, OFF otherwise.",
+" ",
+"SET TAPI MODEM-LIGHTS {[ON], OFF}",
+"  Displays a modem lights indicator on the Windows 95 Taskbar.  Does nothing",
+"  in Windows NT 4.0.",
+" ",
+"SET TAPI MANUAL-DIALING {ON, [OFF]}",
+"  Displays a dialog box during dialing requesting that you manually dial the",
+"  phone before continuing.  Applies only when TAPI MODEM-DIALING is ON.",
+" ",
+"SET TAPI WAIT-FOR-CREDIT-CARD-TONE <seconds>",
+"  Some modems don't support the '$' (BONG) symbol during dialing, which",
+"  means \"wait for credit card tone before continuing.\"  If TAPI recognizes",
+"  the modem as one that does not support BONG, it replaces the '$' with",
+"  <seconds> worth of pauses.  The default is 8 seconds.  This command",
+"  applies only when TAPI MODEM-DIALING is ON",
+" ",
+"SET TAPI PRE-DIAL-TERMINAL {ON, [OFF]}",
+"SET TAPI POST-DIAL-TERMINAL {ON, [OFF]}",
+"  Displays a small terminal window that may be used to communicate with the",
+"  modem or the host prior to or immediately after dialing; applies only when",
+"  TAPI MODEM-DIALING is ON",
+" ",
+"SET TAPI INACTIVITY-TIMEOUT <minutes>",
+"  Specifies the number of minutes of inactivity that may go by before TAPI",
+"  disconnects the line.  The default is 0 which means disable this function.",
+"  Applies only when TAPI MODEM-DIALING is ON.",
+" ",
+"SET TAPI USE-WINDOWS-CONFIGURATION {ON, [OFF]}",
+"  Specifies whether the TAPI modem values for speed, parity, stop bits, flow",
+"  control, etc. are used in preference to the current values specified",
+"  within Kermit-95.",
+" ",
+""};
+#endif /* CK_TAPI */
+
+#endif /* NODIAL */
+
+#ifdef TNCODE
+static char *hmxxiks[] = {
+"Syntax: IKS [ switches ] [ host [ service ] ]",
+"  Establishes a new connection to an Internet Kermit Service daemon.",
+"  Equivalent to SET NETWORK TYPE TCP/IP, SET HOST host KERMIT /TELNET,",
+"  IF SUCCESS CONNECT.  If host is omitted, the previous connection (if any)",
+"  is resumed.  Depending on how Kermit has been built switches may be",
+"  available to require a secure authentication method and bidirectional",
+"  encryption.  See HELP SET TELNET for more info.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /AUTH:<type> is equivalent to SET TELNET AUTH TYPE <type> and",
+"   SET TELOPT AUTH REQUIRED with the following exceptions.  If the type",
+"   is AUTO, then SET TELOPT AUTH REQUESTED is executed and if the type",
+"   is NONE, then SET TELOPT AUTH REFUSED is executed.",
+" ",
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+" /ENCRYPT:<type> is equivalent to SET TELNET ENCRYPT TYPE <type>",
+"   and SET TELOPT ENCRYPT REQUIRED REQUIRED with the following exceptions.",
+"   If the type is AUTO then SET TELOPT AUTH REQUESTED REQUESTED is executed",
+"   and if the type is NONE then SET TELOPT ENCRYPT REFUSED REFUSED is",
+"   executed.",
+" ",
+#endif /* CK_ENCRYPTION */
+" /USERID:[<name>]",
+"   This switch is equivalent to SET LOGIN USERID <name> or SET TELNET",
+"   ENVIRONMENT USER <name>.  If a string is given, it sent to host during",
+"   Telnet negotiations; if this switch is given but the string is omitted,",
+"   no user ID is sent to the host.  If this switch is not given, your",
+"   current USERID value, \\v(userid), is sent.  When a userid is sent to the",
+"   host it is a request to login as the specified user.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /PASSWORD:[<string>]",
+"   This switch is equivalent to SET LOGIN PASSWORD.  If a string is given,",
+"   it is treated as the password to be used (if required) by any Telnet",
+"   Authentication protocol (Kerberos Ticket retrieval, Secure Remote",
+"   Password, or X.509 certificate private key decryption.)  If no password",
+"   switch is specified a prompt is issued to request the password if one",
+"   is required for the negotiated authentication method.",
+#endif /* CK_AUTHENTICATION */
+""};
+
+static char *hmxxtel[] = {
+"Syntax: TELNET [ switches ] [ host [ service ] ]",
+"  Equivalent to SET NETWORK TYPE TCP/IP, SET HOST host [ service ] /TELNET,",
+"  IF SUCCESS CONNECT.  If host is omitted, the previous connection (if any)",
+"  is resumed.  Depending on how Kermit has been built switches may be",
+"  available to require a secure authentication method and bidirectional",
+"  encryption.  See HELP SET TELNET for more info.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /AUTH:<type> is equivalent to SET TELNET AUTH TYPE <type> and",
+"   SET TELOPT AUTH REQUIRED with the following exceptions.  If the type",
+"   is AUTO, then SET TELOPT AUTH REQUESTED is executed and if the type",
+"   is NONE, then SET TELOPT AUTH REFUSED is executed.",
+" ",
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+" /ENCRYPT:<type> is equivalent to SET TELNET ENCRYPT TYPE <type>",
+"   and SET TELOPT ENCRYPT REQUIRED REQUIRED with the following exceptions.",
+"   If the type is AUTO then SET TELOPT AUTH REQUESTED REQUESTED is executed",
+"   and if the type is NONE then SET TELOPT ENCRYPT REFUSED REFUSED is",
+"   executed.",
+" ",
+#endif /* CK_ENCRYPTION */
+" /USERID:[<name>]",
+"   This switch is equivalent to SET LOGIN USERID <name> or SET TELNET",
+"   ENVIRONMENT USER <name>.  If a string is given, it sent to host during",
+"   Telnet negotiations; if this switch is given but the string is omitted,",
+"   no user ID is sent to the host.  If this switch is not given, your",
+"   current USERID value, \\v(userid), is sent.  When a userid is sent to the",
+"   host it is a request to login as the specified user.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /PASSWORD:[<string>]",
+"   This switch is equivalent to SET LOGIN PASSWORD.  If a string is given,",
+"   it is treated as the password to be used (if required) by any Telnet",
+"   Authentication protocol (Kerberos Ticket retrieval, Secure Remote",
+"   Password, or X.509 certificate private key decryption.)  If no password",
+"   switch is specified a prompt is issued to request the password if one",
+"   is required for the negotiated authentication method.",
+#endif /* CK_AUTHENTICATION */
+""};
+
+static char *hxtopt[] = {
+"TELOPT { AO, AYT, BREAK, CANCEL, EC, EL, EOF, EOR, GA, IP, DMARK, NOP, SE,",
+"         SUSP, SB [ option ], DO [ option ], DONT [ option ],",
+"         WILL [ option ], WONT [option] }",
+"  This command lets you send all the Telnet protocol commands.  Note that",
+"  certain commands do not require a response, and therefore can be used as",
+"  nondestructive \"probes\" to see if the Telnet session is still open;",
+"  e.g.:",
+" ",
+"    set host xyzcorp.com",
+"    ...",
+"    telopt nop",
+"    telopt nop",
+"    if fail stop 1 Connection lost",
+" ",
+"  TELOPT NOP is sent twice because the failure of the connection will not",
+"  be detected until the second send is attempted.  This command is meant",
+"  primarily as a debugging tool for the expert user.",
+""};
+#endif /* TNCODE */
+
+#endif /* NOHELP */
+
+/*  D O H L P  --  Give a help message  */
+
+_PROTOTYP( int dohset, (int) );
+#ifndef NOCMDL
+_PROTOTYP( int dohopts, (void) );
+#endif /* NOCMDL */
+#ifndef NOSPL
+_PROTOTYP( int dohfunc, (int) );
+extern struct keytab fnctab[];
+extern int nfuncs;
+#endif /* NOSPL */
+#ifdef OS2
+#ifndef NOKVERBS
+_PROTOTYP( int dohkverb, (int) );
+extern struct keytab kverbs[];
+extern int nkverbs;
+#endif /* NOKVERBS */
+#endif /* OS2 */
+
+#ifndef NOSPL
+static char * hxxdcl[] = {
+"Syntax: ARRAY verb operands...",
+" ",
+"Declares arrays and performs various operations on them.  Arrays have",
+"the following syntax:",
+" ",
+"  \\&a[n]",
+" ",
+"where \"a\" is a letter and n is a number or a variable with a numeric value",
+"or an arithmetic expression.  The value of an array element can be anything",
+"at all -- a number, a character, a string, a filename, etc.",
+" ",
+"The following ARRAY verbs are available:",
+" ",
+"[ ARRAY ] DECLARE arrayname[n] [ = initializers... ]",
+"  Declares an array of the given size, n.  The resulting array has n+1",
+"  elements, 0 through n.  Array elements can be used just like any other",
+"  variables.  Initial values can be given for elements 1, 2, ... by",
+"  including = followed by one or more values separated by spaces.  If you",
+"  omit the size, the array is sized according to the number of initializers;",
+"  if none are given the array is destroyed and undeclared if it already",
+"  existed.  The ARRAY keyword is optional.  Synonym: [ ARRAY ] DCL.",
+" ",
+"[ ARRAY ] UNDECLARE arrayname",
+"  Destroys and undeclares the given array.  Synonym: ARRAY DESTROY.",
+" ",
+"ARRAY SHOW [ arrayname ]",
+"  Displays the contents of the given array.  A range specifier can be",
+"  included to display a segment of the array, e.g. \"array show \\&a[1:24].\""
+,
+"  If the arrayname is omitted, all declared arrays are listed, but their",
+"  contents is not shown.  Synonym: SHOW ARRAY.",
+" ",
+"ARRAY CLEAR arrayname",
+"  Clears all elements of the array, i.e. sets them to empty values.",
+"  You may include a range specifier to clear a segment of the array rather",
+"  than the whole array, e.g. \"array clear \\%a[22:38]\"",
+" ",
+"ARRAY SET arrayname value",
+"  Sets all elements of the array to the given value.  You may specify a",
+"  range to set a segment of the array, e.g. \"array set \\%a[2:9] 0\"",
+" ",
+"ARRAY RESIZE arrayname number",
+"  Changes the size of the given array, which must already exist, to the",
+"  number given.  If the number is smaller than the current size, the extra",
+"  elements are discarded; if it is larger, new empty elements are added.",
+" ",
+"ARRAY COPY array1 array2",
+"  Copys array1 to array2.  If array2 has not been declared, it is created",
+"  automatically.  Range specifiers may be given on one or both arrays.",
+" ",
+"ARRAY LINK array1 arra2",
+"  Makes array1 a link to array2.",
+" ",
+"[ ARRAY ] SORT [ switches ] array-name [ array2 ]",
+"  Sorts the given array lexically according to the switches.  Element 0 of",
+"  the array is excluded from sorting by default.  The ARRAY keyword is",
+"  optional.  If a second array name is given, that array is sorted according",
+"  to the first one.  Switches:",
+" ",
+"  /CASE:{ON,OFF}",
+"    If ON, alphabetic case matters; if OFF it is ignored.  If this switch is",
+"    omitted, the current SET CASE setting applies.",
+" ",
+"  /KEY:number",
+"    \
+Position (1-based column number) at which comparisons begin, 1 by default.",
+" ",
+"  /NUMERIC",
+"    Specifies a numeric rather than lexical sort.",
+" ",
+"  /RANGE:low[:high]",
+"    The range of elements, low through high, to be sorted.  If this switch",
+"    is not given, elements 1 through the dimensioned size are sorted.  If",
+"    :high is omitted, the dimensioned size is used.  To include element 0 in",
+"    a sort, use /RANGE:0 (to sort the whole array) or /RANGE:0:n (to sort",
+"    elements 0 through n).  You can use a range specifier in the array name",
+"    instead of the /RANGE switch.",
+" ",
+"  /REVERSE",
+"    Sort in reverse order.  If this switch is not given, the array is sorted",
+"    in ascending order.",
+" ",
+"Various functions are available for array operations; see HELP FUNCTION for",
+"details.  These include \\fdimension(), \\farraylook(), \\ffiles(), \
+\\fsplit(),",
+"and many more.",
+""};
+#endif /* NOSPL */
+
+#ifdef ZCOPY
+static char * hmxxcpy[] = {
+"Syntax: COPY [ switches ] file1 file2",
+"  Copies the source file (file1) to the destination file (file2).  If file2",
+"  is a directory, file1 can contain wildcards to denote a group of files to",
+"  be copied to the given directory.  Switches:",
+" ",
+"  /LIST",
+"    Print the filenames and status while copying.  Synonyms: /LOG, /VERBOSE",
+" ",
+"  /NOLIST",
+"    Copy silently (default). Synonyms: /NOLOG, /QUIET",
+" ",
+"  /SWAP-BYTES",
+"    Swap bytes while copying.",
+#ifndef NOSPL
+" ",
+"  /FROMB64",
+"    Convert from Base64 encoding while copying.",
+" ",
+"  /TOB64",
+"    Convert to Base64 encoding while copying.",
+#endif /* NOSPL */
+""
+};
+#endif /* ZCOPY */
+
+#ifndef NOFRILLS
+static char * hmxxren[] = {
+#ifdef LOCUS
+"  If LOCUS is REMOTE or LOCUS is AUTO and you have an FTP connection,",
+"  this command is equivalent to REMOTE RENAME (RREN).  Otherwise:",
+" ",
+#endif /* LOCUS */
+"Syntax: RENAME [ switches ] name1 name2",
+"  Renames the source file (name1) to the target name2.  If name2 is a",
+"  directory, name1 is allowed to contain wildcards, and the file(s) matching",
+"  name1 are moved to directory name2, subject to rules of the underlying",
+"  operating system regarding renaming across disk boundaries, etc.  If name2",
+"  is not a directory, name1 may not include wildcards, and the file whose",
+"  name is name1 is renamed to name2.  Switches:",
+" ",
+"  /LIST",
+"    Print the filenames and status while renaming.  Synonyms: /LOG, /VERBOSE",
+" ",
+"  /NOLIST",
+"    Rename silently (default). Synonyms: /NOLOG, /QUIET",
+""
+};
+#endif /* NOFRILLS */
+
+static char *
+cmdlhlp[] = {
+"Command-line options are given after the program name in the system",
+"command that you use to start Kermit.  Example:",
+" ",
+" kermit -i -s oofa.exe",
+" ",
+"tells Kermit to send (-s) the file oofa.exe in binary (-i) mode.",
+" ",
+"Command-line options are case-sensitive; \"-s\" is different from \"-S\".",
+#ifdef VMS
+"In VMS, uppercase options must be enclosed in doublequotes: ",
+" ",
+" $ kermit \"-Y\" \"-S\" -s oofa.txt ",
+#endif /* VMS */
+" ",
+"If any \"action options\" are included on the command line, Kermit exits",
+"after executing its command-line options.  If -S is included, or no action",
+"options were given, Kermit enters its interactive command parser and",
+"issues its prompt.",
+" ",
+"Command-line options are single characters preceded by dash (-).  Some",
+"require an \"argument,\" others do not.  If an argument contains spaces, it",
+"must be enclosed in doublequotes:",
+" ",
+" kermit -s \"filename with spaces\"",
+" ",
+"\
+An option that does not require an argument can be bundled with other options:"
+,
+" ",
+" kermit -Qis oofa.exe",
+" ",
+"Exceptions to the rules:",
+" ",
+" . If the first command-line option is a filename, Kermit executes commands",
+"   from the file.  Additional command-line options can follow the filename.",
+" ",
+" . The special option \"=\" (equal sign) or \"--\" (double hyphen) means to",
+"   treat the rest of the command line as data, rather than commands; this",
+"   data is placed in the argument vector array, \\&@[], along with the other",
+"   items on the command line, and also in the top-level \\%1..\\%9 variables."
+,
+" ",
+#ifdef KERBANG
+" . A similar option \"+\" (plus sign) means: the name of a Kermit script",
+"   file follows.  This file is to be executed, and its name assigned to \\%0",
+"   and \\&_[0].  All subsequent command-line arguments are to be ignored by",
+"   Kermit but made available to the script as \\%1, \\%2, ..., as well as",
+"   in the argument-vector arrays.  The initialization file is not executed",
+"   automatically in this case.",
+" ",
+#endif /* KERBANG */
+" . The -s option can accept multiple filenames, separated by spaces.",
+" ",
+" . the -j and -J options allow an optional second argument, the TCP port",
+"   name or number.",
+" ",
+"Type \"help options all\" to list all the command-line options.",
+"Type \"help option x\" to see the help message for option x.",
+" ",
+"Kermit also offers a selection of \"extended command-line\" options.",
+"These begin with two dashes, followed by a keyword, and then, if the option",
+"has arguments, a colon (:) or equal sign (=) followed by the argument.",
+"Unlike single-letter options, extended option keywords aren't case sensitive",
+"and they can be abbreviated to any length that still distinguishes them from",
+"other extended-option keywords.  Example:",
+" ",
+"  kermit --banner:oofa.txt",
+" ",
+"which designates the file oofa.txt to be printed upon startup, rather than",
+"the built-in banner (greeting) text.  To obtain a list of available",
+"extended options, type \"help extended-options ?\".  To get help about all",
+"extended options, type \"help extended-options\".  To get help about a",
+"particular extended option, type \"help extended-option xxx\", where \"xxx\"",
+"is the option keyword.",
+#ifdef COMMENT
+#ifndef NOIKSD
+" ",
+"At present, most of the extended options apply only to the Internet Kermit",
+"Service Daemon (IKSD).  Type \"help iksd\" for details.",
+#endif /* NOIKSD */
+#endif /* COMMENT */
+""
+};
+
+#ifndef NOHELP
+#ifndef NOCMDL
+int
+doxopts() {
+    extern char * xopthlp[], * xarghlp[];
+    extern struct keytab xargtab[];
+    extern int nxargs;
+    int i, x, y, n = 0;
+#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 */
+    y = cmkey(xargtab,
+              nxargs,
+              "Extended argument without the \"--\" prefix",
+              "",
+              xxstring
+              );
+    if (y == -3) {
+	printf("\n");
+        if ((x = cmcfm()) < 0)
+	  return(x);
+        for (i = 0; i <= XA_MAX; i++) {
+            if (xopthlp[i]) {
+                printf("%s\n",xopthlp[i]);
+                printf("   %s\n",xarghlp[i]);
+                printf("\n");
+                n += 3;
+                if (n > (cmd_rows - 6)) {
+                    if (!askmore())
+                      return(0);
+                    else
+                      n = 0;
+                }
+            }
+        }
+        return(1);
+    } else if (y < 0)
+      return(y);
+    if ((x = cmcfm()) < 0)
+      return(x);
+    printf("\n%s\n",xopthlp[y]);
+    printf("   %s\n\n",xarghlp[y]);
+    return(1);
+}
+
+int
+dohopts() {
+    int i, n, x, y, z, all = 0, msg = 0;
+    char *s;
+    extern char *opthlp[], *arghlp[];
+    extern char * xopthlp[], * xarghlp[];
+    extern int optact[];
+    if ((x = cmtxt("A command-line option character,\n\
+or the word ALL, or carriage return for an overview",
+                   "", &s, xxstring)) < 0)
+      return(x);
+    if (!*s)
+      msg = 1;
+    else if (!strcmp(s,"all") || (!strcmp(s,"ALL")))
+      all = 1;
+    else if (*s == '-')                 /* Be tolerant of leading hyphen */
+      s++;
+    if (!all && (int)strlen(s) > 1) {
+        printf("?A single character, please, or carriage to list them all.\n");
+        return(-9);
+    }
+    if (all) {
+        y = 33;
+        z = 127;
+    } else {
+        y = *s;
+        z = (y == 0) ? 127 : y;
+        if (y == 0) y = 33;
+    }
+#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");
+    for (i = 0, n = 1; msg != 0 && *cmdlhlp[i]; i++) {
+        printf("%s\n",cmdlhlp[i]);
+        if (++n > (cmd_rows - 3)) {
+           if (!askmore())
+             return(0);
+           else
+             n = 0;
+        }
+    }
+    if (all) {
+        printf("The following command-line options are available:\n\n");
+        n += 2;
+    }
+    for (i = y; msg == 0 && i <= z; i++) {
+        if (!opthlp[i])
+          continue;
+        if (arghlp[i]) {                /* Option with arg */
+            printf(" -%c <arg>%s\n",(char)i,(optact[i]?" (action option)":""));
+
+            printf("     %s\n",opthlp[i]);
+            printf("     Argument: %s\n\n",arghlp[i]);
+            x = 4;
+        } else {                        /* Option without arg */
+            printf(" -%c  %s%s\n",
+                   (char)i, opthlp[i],
+                   (optact[i]?" (action option)":"")
+                  );
+            printf("     Argument: (none)\n\n");
+            x = 3;
+        }
+        n += x;
+        if (n > (cmd_rows - x - 1)) {
+            if (!askmore())
+              return(0);
+           else
+              n = 0;
+        }
+    }
+    if (all) {				/* Jeff, Jan 2003 */
+        printf("\n");
+        if (++n >= cmd_rows) {
+            if (!askmore())
+              return(0);
+	    else
+              n = 0;
+        }
+        printf("The following extended options are available:\n");
+        if (++n >= cmd_rows) {
+            if (!askmore())
+              return(0);
+	    else
+              n = 0;
+        }
+        printf("\n");
+        if (++n >= cmd_rows) {
+            if (!askmore())
+              return(0);
+	    else
+              n = 0;
+        }
+        for (i = 0; i <= XA_MAX; i++) {
+            if (xopthlp[i]) {
+                printf("%s\n",xopthlp[i]);
+                printf("   %s\n",xarghlp[i]);
+                printf("\n");
+                n += 3;
+                if (n > (cmd_rows - 4)) {
+                    if (!askmore())
+		      return(0);
+                    else
+		      n = 0;
+                }
+            }
+        }
+    }
+    return(1);
+}
+#endif /* NOCMDL */
+#endif /* NOHELP */
+
+#ifdef CKCHANNELIO
+static char * hxxfile[] = {
+"Syntax: FILE <subcommand> [ switches ] <channel> [ <data> ]",
+"  Opens, closes, reads, writes, and manages local files.",
+" ",
+"The FILE commands are:",
+" ",
+"  FILE OPEN   (or FOPEN)   -- Open a local file.",
+"  FILE CLOSE  (or FCLOSE)  -- Close an open file.",
+"  FILE READ   (or FREAD)   -- Read data from an open file.",
+"  FILE WRITE  (or FWRITE)  -- Write data to an open file.",
+"  FILE LIST   (or FLIST)   -- List open files.",
+"  FILE STATUS (or FSTATUS) -- Show status of a channel.",
+"  FILE REWIND (or FREWIND) -- Rewind an open file",
+"  FILE COUNT  (or FCOUNT)  -- Count lines or bytes in an open file",
+"  FILE SEEK   (or FSEEK)   -- Seek to specified spot in an open file.",
+"  FILE FLUSH  (or FFLUSH)  -- Flush output buffers for an open file.",
+" ",
+"Type HELP FILE OPEN or HELP FOPEN for details about FILE OPEN;",
+"type HELP FILE CLOSE or HELP FCLOSE for details about FILE CLOSE, and so on.",
+" ",
+"The following variables are related to the FILE command:",
+" ",
+"  \\v(f_max)     -- Maximum number of files that can be open at once",
+"  \\v(f_error)   -- Completion code of most recent FILE command or function",
+"  \\v(f_count)   -- Result of most recent FILE COUNT command",
+" ",
+"The following functions are related to the FILE command:",
+" ",
+"  \\F_eof()      -- Check if channel is at EOF",
+"  \\F_pos()      -- Get channel read/write position (byte number)",
+"  \\F_line()     -- Get channel read/write position (line number)",
+"  \\F_handle()   -- Get file handle",
+"  \\F_status()   -- Get channel status",
+"  \\F_getchar()  -- Read character",
+"  \\F_getline()  -- Read line",
+"  \\F_getblock() -- Read block",
+"  \\F_putchar()  -- Write character",
+"  \\F_putline()  -- Write line",
+"  \\F_putblock() -- Write block",
+"  \\F_errmsg()   -- Error message from most recent FILE command or function",
+" ",
+"Type HELP <function-name> for information about each one.",
+""
+};
+
+static char * hxxf_op[] = {
+"Syntax: FILE OPEN [ switches ] <variable> <filename>",
+"  Opens the file indicated by <filename> in the mode indicated by the",
+"  switches, if any, or if no switches are included, in read-only mode, and",
+"  assigns a channel number for the file to the given variable.",
+"  Synonym: FOPEN.  Switches:",
+" ",
+"/READ",
+"  Open the file for reading.",
+" ",
+"/WRITE",
+"  Open the file for writing.  If /READ was not also specified, this creates",
+"  a new file.  If /READ was specifed, the existing file is preserved, but",
+"  writing is allowed.  In both cases, the read/write pointer is initially",
+"  at the beginning of the file.",
+" ",
+"/APPEND",
+"  If the file does not exist, create a new file and open it for writing.",
+"  If the file exists, open it for writing, but with the write pointer",
+"  positioned at the end.",
+" ",
+"/BINARY",
+#ifdef VMS
+"  Opens the file in binary mode to inhibit end-of-line conversions.",
+#else
+#ifdef OS2
+"  Opens the file in binary mode to inhibit end-of-line conversions.",
+#else
+#ifdef UNIX
+"  This option is ignored in UNIX.",
+#else
+"  This option is ignored on this platform.",
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* VMS */
+" ",
+"Switches can be combined in an way that makes sense and is supported by the",
+"underlying operating system.",
+""
+};
+
+static char * hxxf_cl[] = {
+"Syntax: FILE CLOSE <channel>",
+"  Closes the file on the given channel if it was open.",
+"  Also see HELP FILE OPEN.  Synonym: FCLOSE.",
+""
+};
+
+static char * hxxf_fl[] = {
+"Syntax: FILE FLUSH <channel>",
+"  Flushes output buffers on the given channel if it was open, forcing",
+"  all material previously written to be committed to disk.  Synonym: FFLUSH.",
+"  Also available as \\F_flush().",
+""
+};
+
+static char * hxxf_li[] = {
+"Syntax: FILE LIST",
+"  Lists the channel number, name, modes, and position of each file opened",
+"  with FILE OPEN.  Synonym: FLIST.",
+""
+};
+
+static char * hxxf_re[] = {
+"Syntax: FILE READ [ switches ] <channel> [ <variable> ]",
+"  Reads data from the file on the given channel number into the <variable>,",
+"  if one was given; if no variable was given, the result is printed on",
+"  the screen.  The variable should be a macro name rather than a \\%x",
+"  variable or array element if you want backslash characters in the file to",
+"  be taken literally.  Synonym: FREAD.  Switches:",
+" ",
+"/LINE",
+"  Specifies that a line of text is to be read.  A line is defined according",
+"  to the underlying operating system's text-file format.  For example, in",
+"  UNIX a line is a sequence of characters up to and including a linefeed.",
+"  The line terminator (if any) is removed before assigning the text to the",
+"  variable.  If no switches are included with the FILE READ command, /LINE",
+"  is assumed.",
+" ",
+"/SIZE:number",
+"  Specifies that the given number of bytes (characters) is to be read.",
+"  This gives a semblance of \"record i/o\" for files that do not necessarily",
+"  contain lines.  The resulting block of characters is assigned to the",
+"  variable without any editing.",
+" ",
+"/CHARACTER",
+"  Equivalent to /SIZE:1.  If FILE READ /CHAR succeeds but the <variable> is",
+"  empty, this indicates a NUL byte was read.",
+" ",
+"/TRIM",
+"  Tells Kermit to trim trailing whitespace when used with /LINE.  Ignored",
+"  if used with /CHAR or /SIZE.",
+" ",
+"/UNTABIFY",
+"  Tells Kermit to convert tabs to spaces (assuming tabs set every 8 spaces)",
+"  when used with /LINE.  Ignored if used with /CHAR or /SIZE.",
+" ",
+"Synonym: FREAD.",
+"Also available as \\F_getchar(), \\F_getline(), \\F_getblock().",
+""
+};
+
+static char * hxxf_rw[] = {
+"Syntax: FILE REWIND <channel>",
+"  If the channel is open, moves the read/write pointer to the beginning of",
+"  the file.  Equivalent to FILE SEEK <channel> 0.  Synonym: FREWIND.",
+"  Also available as \\F_rewind().",
+""
+};
+
+static char * hxxf_se[] = {
+"Syntax: FILE SEEK [ switches ] <channel> { [{+,-}]<number>, EOF }",
+"  Switches are /BYTE, /LINE, /RELATIVE, ABSOLUTE.",
+"  Moves the file pointer for this file to the given position in the",
+"  file.  Subsequent FILE READs or WRITEs will take place at that position.",
+"  If neither the /RELATIVE nor /ABSOLUTE switch is given, an unsigned",
+"  <number> is absolute; a signed number is relative.  EOF means to move to",
+"  the end of the file.  Synonym: FSEEK.  Also available as \\F_seek().",
+""
+};
+
+static char * hxxf_st[] = {
+"Syntax: FILE STATUS <channel>",
+"  If the channel is open, this command shows the name of the file, the",
+"  switches it was opened with, and the current read/write position.",
+"  Synonym: FSTATUS",
+""
+};
+
+static char * hxxf_co[] = {
+"Syntax: FILE COUNT [ { /BYTES, /LINES, /LIST, /NOLIST } ] <channel>",
+"  If the channel is open, this command prints the nubmer of bytes (default)",
+"  or lines in the file if at top level or if /LIST is included; if /NOLIST",
+"  is given, the result is not printed.  In all cases the result is assigned",
+"  to \\v(f_count).  Synonym: FCOUNT",
+""
+};
+
+static char * hxxf_wr[] = {
+"FILE WRITE [ switches ] <channel> <text>",
+"  Writes the given text to the file on the given channel number.  The <text>",
+"  can be literal text or a variable, or any combination.  If the text might",
+"  contain leading or trailing spaces, it must be enclosed in braces if you",
+"  want to preserve them.  Synonym: FWRITE.  Switches:",
+" ",
+"/LINE",
+"  Specifies that an appropriate line terminator is to be added to the",
+"  end of the <text>.  If no switches are included, /LINE is assumed.",
+" ",
+"/SIZE:number",
+"  Specifies that the given number of bytes (characters) is to be written.",
+"  If the given <text> is longer than the requested size, it is truncated;",
+"  if is shorter, it is padded according /LPAD and /RPAD switches.  Synonym:",
+"  /BLOCK.",
+" ",
+"/LPAD[:value]",
+"  If /SIZE was given, but the <text> is shorter than the requested size,",
+"  the text is padded on the left with sufficient copies of the character",
+"  whose ASCII value is given to write the given length.  If no value is",
+"  specified, 32 (the code for Space) is used.  The value can also be 0 to",
+"  write the indicated number of NUL bytes.  If /SIZE was not given, this",
+"  switch is ignored.",
+" ",
+"/RPAD[:value]",
+"  Like LPAD, but pads on the right.",
+" ",
+"/STRING",
+"  Specifies that the <text> is to be written as-is, with no terminator added."
+,
+" ",
+"/CHARACTER",
+"  Specifies that one character should be written.  If the <text> is empty or",
+"  not given, a NUL character is written; otherwise the first character of",
+"  <text> is given.",
+" ",
+"Synonym FWRITE.",
+"Also available as \\F_putchar(), \\F_putline(), \\F_putblock().",
+""
+};
+
+static int
+dohfile(cx) int cx; {
+    extern struct keytab fctab[];
+    extern int nfctab;
+    int x;
+    if (cx == XXFILE) {                 /* FILE command was given */
+        /* Get subcommand */
+        if ((cx = cmkey(fctab,nfctab,"Operation","",xxstring)) < 0) {
+            if (cx == -3) {
+                if ((x = cmcfm()) < 0)
+                  return(x);
+                cx = XXFILE;
+            } else
+              return(cx);
+        }
+        if ((x = cmcfm()) < 0)
+          return(x);
+        switch (cx) {
+          case FIL_CLS: cx = XXF_CL; break;
+          case FIL_FLU: cx = XXF_FL; break;
+          case FIL_LIS: cx = XXF_LI; break;
+          case FIL_OPN: cx = XXF_OP; break;
+          case FIL_REA: cx = XXF_RE; break;
+          case FIL_REW: cx = XXF_RW; break;
+          case FIL_SEE: cx = XXF_SE; break;
+          case FIL_STA: cx = XXF_ST; break;
+          case FIL_WRI: cx = XXF_WR; break;
+          case FIL_COU: cx = XXF_CO; break;
+        }
+    }
+    switch (cx) {
+      case XXFILE: return(hmsga(hxxfile));
+      case XXF_CL: return(hmsga(hxxf_cl));
+      case XXF_FL: return(hmsga(hxxf_fl));
+      case XXF_LI: return(hmsga(hxxf_li));
+      case XXF_OP: return(hmsga(hxxf_op));
+      case XXF_RE: return(hmsga(hxxf_re));
+      case XXF_RW: return(hmsga(hxxf_rw));
+      case XXF_SE: return(hmsga(hxxf_se));
+      case XXF_ST: return(hmsga(hxxf_st));
+      case XXF_WR: return(hmsga(hxxf_wr));
+      case XXF_CO: return(hmsga(hxxf_co));
+      default:
+        return(-2);
+    }
+}
+#endif /* CKCHANNELIO */
+
+int
+dohlp(xx) int xx; {
+    int x,y;
+
+    debug(F101,"DOHELP xx","",xx);
+    if (xx < 0) return(xx);
+
+#ifdef NOHELP
+    if ((x = cmcfm()) < 0)
+      return(x);
+    printf("\n%s, Copyright (C) 1985, 2004,",versio);
+#ifndef NOIKSD
+    if (inserver)
+      return(hmsga(tophlpi));
+    else
+#endif /* IKSD */
+      return(hmsga(tophlp));
+
+#else /* help is available */
+
+    if (helpfile)
+      return(dotype(helpfile,xaskmore,0,0,NULL,0,NULL,0,0,NULL,0));
+
+#ifdef CKCHANNELIO
+    if (xx == XXFILE)
+      return(dohfile(xx));
+    else if (xx == XXF_RE || xx == XXF_WR || xx == XXF_OP ||
+             xx == XXF_CL || xx == XXF_SE || xx == XXF_RW ||
+             xx == XXF_FL || xx == XXF_LI || xx == XXF_ST || xx == XXF_CO)
+      return(dohfile(xx));
+#endif /* CKCHANNELIO */
+
+    switch (xx) {
+
+#ifndef NOSPL
+case XXASS:                             /* ASSIGN */
+    return(hmsga(hxxass));
+
+case XXASK:                             /* ASK */
+case XXASKQ:                            /* ASKQ */
+    return(hmsga(hxxask));
+
+case XXAPC:
+    return(hmsg("Syntax: APC text\n\
+  Echoes the text within a VT220/320/420 Application Program Command."));
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+case XXBUG:
+    return(hmsg("Describes how to get technical support."));
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+case XXBEEP:
+#ifdef OS2
+    return(hmsg("Syntax: BEEP [ { ERROR, INFORMATION, WARNING } ]\n\
+  Generates a bell according to the current settings.  If SET BELL is set to\n\
+  \"system-sounds\" then the appropriate System Sound will be generated.\n\
+  Default is INFORMATION."));
+#else /* OS2 */
+    return(hmsg("Syntax: BEEP\n\
+Sends a BEL character to your terminal."));
+#endif /* OS2 */
+#endif /* NOSPL */
+
+case XXBYE:                             /* BYE */
+    return(hmsg(hmxxbye));
+
+case XXCHK:                             /* check */
+    return(hmsg("\
+Syntax: CHECK name\n\
+  Checks\
+  to see if the named feature is included in this version of Kermit.\n\
+  To list the features you can check, type \"check ?\"."));
+
+#ifndef NOFRILLS
+case XXCLE:                             /* clear */
+    return(hmsga(hmxxcle));
+#endif /* NOFRILLS */
+
+case XXCLO:                             /* close */
+    return(hmsga(hmxxclo));
+
+case XXCOM:                             /* comment */
+#ifndef STRATUS /* Can't use # for comments in Stratus VOS */
+    return(hmsg("\
+Syntax: COMMENT text\n\
+Example: COMMENT - this is a comment.\n\
+  Introduces a comment.  Beginning of command line only.  Commands may also\n\
+  have trailing comments, introduced by ; or #."));
+#else
+    return(hmsg("\
+Syntax: COMMENT text\n\
+Example: COMMENT - this is a comment.\n\
+  Introduces a comment.  Beginning of command line only.  Commands may also\n\
+  have trailing comments, introduced by ; (semicolon)."));
+#endif /* STRATUS */
+
+#ifndef NOLOCAL
+case XXCON:                             /* CONNECT */
+case XXCQ:                              /* CQ == CONNECT /QUIETLY */
+    hmsga(hmxxcon);
+    printf("Your escape character is Ctrl-%c (ASCII %d, %s)\r\n",
+           ctl(escape), escape, (escape == 127 ? "DEL" : ccntab[escape]));
+    return(0);
+#endif /* NOLOCAL */
+
+#ifdef ZCOPY
+case XXCPY:
+    return(hmsga(hmxxcpy));
+#endif /* ZCOPY */
+
+#ifdef NT
+case XXLINK:
+return(hmsg(
+"  LINK source destination\n\
+   creates a hard link to the file specified by source to the filename\n\
+   specified by destination.  Hard links are only supported on NTFS.\n\
+   destination can either be a filename or a directory.  source may\n\
+   contain wildcards if destination is a directory."));
+#endif /* NT */
+
+#ifndef NOFRILLS
+case XXLREN:                            /* LRENAME */
+    return(hmsg(
+"  LRENAME is an alias for the RENAME command forcing it to execute\n\
+  on the local computer.  Also see: RENAME, RRENAME, SET LOCUS."));
+
+case XXREN:
+    return(hmsga(hmxxren));
+#endif /* NOFRILLS */
+
+case XXCDUP:                             /* CDUP */
+case XXLCDU:
+    return(hmsg(
+"Change working directory to the one just above the current one."));
+
+case XXLCWD:
+    return(hmsg(
+"  LCD (LCWD) is an alias for the CD (CWD) command forcing it to execute\n\
+  on the local computer.  Also see: CD, CDUP, RCD, SET LOCUS."));
+
+case XXCWD:                             /* CD / CWD */
+    return(hmsga(hmxxcwd));
+
+#ifndef NOSPL
+case XXKCD:
+    return(hmsga(hmxxkcd));
+
+case XXARRAY:
+case XXDCL:                             /* DECLARE */
+case XXSORT:
+    return(hmsga(hxxdcl));
+
+case XXDEF:                             /* DEFINE */
+#ifndef NOSPL
+    if (hlptok)                         /* What they actually typed... */
+      if (hlptok[0] == '.')
+        return(hmsga(hxxdot));
+#endif /* NOSPL */
+    return(hmsga(hxxdef));
+
+case XXUNDEF:                           /* UNDEFINE */
+    return(hmsg("Syntax:  UNDEFINE variable-name\n\
+  Undefines a macro or variable."));
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+case XXLDEL:
+    return(hmsg(
+"  LDELETE is an alias for the DELETE command forcing it to execute\n\
+  on the local computer.  Also see: DELETE, RDELETE, SET LOCUS."));
+
+case XXDEL:                             /* delete */
+    return(hmsga(hmxxdel));
+#endif /* NOFRILLS */
+
+#ifndef NODIAL
+case XXDIAL:                            /* DIAL, etc... */
+    return(hmsga(hxxdial));
+
+case XXPDIA:                            /* PDIAL */
+    return(hmsg("Syntax: PDIAL phonenumber\n\
+  Partially dials a phone number.  Like DIAL but does not wait for carrier\n\
+  or CONNECT message."));
+
+case XXRED:
+    return(hmsg("Redial the number given in the most recent DIAL commnd."));
+
+case XXANSW:                            /* ANSWER */
+    return(hmsga(hxxansw));
+
+case XXLOOK:                            /* LOOKUP number in directory */
+    return(hmsga(hxxlook));
+#endif /* NODIAL */
+
+case XXLDIR:                            /* LDIRECTORY */
+    return(hmsg(
+"  LDIRIRECTORY is an alias for the DIRECTORY command forcing it to execute\n\
+  on the local computer.  Also see: DIRECTORY, SET LOCUS, RDIRECTORY."));
+
+case XXDIR:                             /* DIRECTORY */
+    return(hmsga(hmxxdir));
+
+case XXLMKD:                            /* LMKDIR */
+    return(hmsg(
+"  LMKDIR is an alias for the MKDIR command forcing it to execute\n\
+  on the local computer.  Also see: MKDIR, RMKDIR, SET LOCUS."));
+
+case XXMKDIR:                           /* MKDIR */
+    return(hmsg("Creates a directory.  Also see LRMDIR, RRMDIR, SET LOCUS."));
+
+case XXLRMD:                            /* LRMDIR */
+    return(hmsg(
+"  LRMDIR is an alias for the RMDIR command forcing it to execute\n\
+  on the local computer.  Also see: RMDIR, RRMDIR, SET LOCUS."));
+
+case XXRMDIR:                           /* RMDIR */
+    return(hmsg("Removes a directory.  Also see LRMDIR, RRMDIR, SET LOCUS."));
+
+case XXLS:
+#ifdef UNIXOROSK
+    return(hmsg("Syntax: LS [ args ]\n\
+  Runs \"ls\" with the given arguments."));
+#else
+    return(hmsga(hmxxdir));
+#endif /* UNIXOROSK */
+
+#ifndef NOSERVER
+#ifndef NOFRILLS
+case XXDIS:
+    return(hmsg("Syntax: DISABLE command\n\
+  Security for the Kermit server.  Prevents the client Kermit program from\n\
+  executing the named REMOTE command, such as CD, DELETE, RECEIVE, etc."));
+#endif /* NOFRILLS */
+#endif /* NOSERVER */
+
+#ifndef NOSPL
+case XXDO:                              /* do */
+    return(hmsg("Syntax: [ DO ] macroname [ arguments ]\n\
+  Executes a macro that was defined with the DEFINE command.  The word DO\n\
+  can be omitted.  Trailing argument words, if any, are automatically\n\
+  assigned to the macro argument variables \\%1 through \\%9."));
+#endif /* NOSPL */
+
+#ifndef NOSPL
+case XXDEC:
+    return(hmsga(hxxdec));
+#endif /* NOSPL */
+
+case XXECH:                             /* echo */
+    return(hmsg("Syntax: ECHO text\n\
+  Displays the text on the screen, followed by a line terminator.  The ECHO\n\
+  text may contain backslash codes.  Example: ECHO \\7Wake up!\\7.  Also see\n\
+  XECHO and WRITE SCREEN."));
+
+case XXXECH:                            /* xecho */
+    return(hmsg("Syntax: XECHO text\n\
+  Just like ECHO but does not add a line terminator to the text.  See ECHO."));
+
+case XXVOID:
+    return(hmsg("Syntax: VOID text\n\
+  Like ECHO but doesn't print anything; can be used to invoke functions\n\
+  when you don't need to display or use their results."));
+
+#ifndef NOSERVER
+#ifndef NOFRILLS
+case XXENA:
+    return(hmsg("Syntax: ENABLE capability\n\
+  For use with server mode.  Allows the client Kermit program access to the\n\
+  named capability, such as CD, DELETE, RECEIVE, etc.  Opposite of DISABLE."));
+#endif /* NOFRILLS */
+#endif /* NOSERVER */
+
+#ifndef NOSPL
+case XXEND:                             /* end */
+    return(hmsg("Syntax: END [ number [ message ] ]\n\
+  Exits from the current macro or TAKE file, back to wherever invoked from.\n\
+  Number is return code.  Message, if given, is printed."));
+
+case XXEVAL:                            /* evaluate */
+    return(hmsga(hmxxeval));
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+case XXERR:                             /* e-packet */
+    return(hmsg("Syntax: E-PACKET\n\
+  Sends an Error packet to the other Kermit."));
+#endif /* NOFRILLS */
+
+case XXEXI:                             /* exit */
+case XXQUI:
+    return(hmsga(hmxxexit));
+
+case XXFIN:
+    return(hmsg("Syntax: FINISH\n\
+  Tells the remote Kermit server to shut down without logging out."));
+
+#ifndef NOSPL
+  case XXFOR:
+    return(hmsga(forhlp));
+#endif /* NOSPL */
+
+  case XXGET:
+    return(hmsga(hmxxget));
+  case XXMGET:
+    return(hmsga(hmxxmget));
+
+#ifndef NOSPL
+#ifndef NOFRILLS
+  case XXGOK:
+    return(hmsg("Syntax: GETOK [ switches ] prompt\n\
+  Prints the prompt, makes user type 'yes', 'no', or 'ok', and sets SUCCESS\n\
+  or FAILURE accordingly.  The optional switches are the same as for ASK."));
+#endif /* NOFRILLS */
+#endif /* NOSPL */
+
+#ifndef NOSPL
+  case XXGOTO:
+    return(hmsg("Syntax: GOTO label\n\
+  In a TAKE file or macro, go to the given label.  A label is a word on the\n\
+  left margin that starts with a colon (:).  Example:\n\n\
+  :oofa\n\
+  echo Hello!\n\
+  goto oofa"));
+#endif /* NOSPL */
+
+  case XXHAN:
+    return(hmsg("Syntax: HANGUP\n\
+Hang up the phone or network connection."));
+
+  case XXHLP:
+/*
+  We get confirmation here, even though we do it again in hmsga(), to prevent
+  the Copyright message from being printed prematurely.  This doesn't do any
+  harm, because the first call to cmcfm() sets cmflgs to 1, making the second
+  call return immediately.
+*/
+    if ((x = cmcfm()) < 0)
+      return(x);
+
+    if (helpfile) {
+        printf("\n%s, Copyright (C) 1985, 2004,\n\
+Trustees of Columbia University in the City of New York.\n\n",versio);
+        return(dotype(helpfile,xaskmore,3,0,NULL,0,NULL,0,0,NULL,0));
+    } else {
+        printf("\n%s, Copyright (C) 1985, 2004,",versio);
+        return(hmsga(tophlp));
+    }
+
+case XXINT:
+#ifdef OS2
+    return(hmsg("Give a brief introduction to C-Kermit."));
+#else
+    return(hmsg("Give a brief introduction to Kermit 95."));
+#endif /* OS2 */
+
+#ifndef NOSPL
+case XXIF:
+    return(hmsga(ifhlp));
+
+case XXINC:
+    return(hmsga(hxxinc));
+
+case XXINP:
+   return(hmsga(hxxinp));
+#endif /* NOSPL */
+
+#ifdef CK_MINPUT
+case XXMINP:
+    return(hmsga(hmxxminp));
+#endif /* CK_MINPUT */
+
+#ifndef NOSPL
+case XXREI:
+    return(hmsg("Syntax: REINPUT n string\n\
+  Looks for the string in the text that has recently been INPUT, set SUCCESS\n\
+  or FAILURE accordingly.  Timeout, n, must be specified but is ignored."));
+#endif /* NOSPL */
+
+#ifndef NOSPL
+case XXLBL:
+    return(hmsg("\
+  Introduces a label, like :loop, for use with GOTO in TAKE files or macros.\n\
+See GOTO."));
+#endif /* NOSPL */
+
+case XXLOG:
+    return(hmsga(hmxxlg));
+
+#ifndef NOSCRIPT
+case XXLOGI:
+    return(hmsga(hmxxlogi));
+#endif
+
+#ifndef NOFRILLS
+case XXMAI:
+    return(hmsg("Syntax: MAIL filename address\n\
+  Equivalent to SEND /MAIL:address filename."));
+#endif /* NOFRILLS */
+
+#ifndef NOMSEND
+case XXMSE:
+    return(hmsga(hmxxmse));
+
+case XXADD:
+    return(hmsga(hmxxadd));
+
+case XXMMOVE:
+    return(hmsg("MMOVE is exactly like MSEND, except each file that is\n\
+sent successfully is deleted after it is sent."));
+#endif /* NOMSEND */
+
+#ifndef NOSPL
+case XXOPE:
+    return(hmsga(openhlp));
+#endif /* NOSPL */
+
+case XXNEW:
+    return(hmsg(
+"  Prints news of new features since publication of \"Using C-Kermit\"."));
+
+case XXUPD:
+    return(hmsg(
+"  New features are described in the online Kermit 95 manual,\n\
+   accessible via the MANUAL command."));
+
+#ifndef NOSPL
+case XXOUT:
+    return(hmsga(hxxout));
+#endif /* NOSPL */
+
+#ifdef ANYX25
+#ifndef IBMX25
+case XXPAD:
+    return(hmsga(hxxpad));
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifndef NOSPL
+case XXPAU:
+    return(hmsga(hxxpau));
+
+case XXMSL:
+    return(hmsga(hxxmsl));
+#endif /* NOSPL */
+
+#ifdef TCPSOCKET
+case XXPNG:
+    return(hmsg("Syntax: PING [ IP-hostname-or-number ]\n\
+  Checks if the given IP network host is reachable.  Default host is from\n\
+  most recent SET HOST or TELNET command.  Runs system PING program, if any.")
+           );
+
+case XXFTP:
+#ifdef SYSFTP
+    return(hmsg("Syntax: FTP [ IP-hostname-or-number ]\n\
+  Makes an FTP connection to the given IP host or, if no host specified, to\n\
+  the current host.  Uses the system's FTP program, if any."));
+#else
+#ifndef NOFTP
+    return(doftphlp());
+#endif /* NOFTP */
+#endif /* SYSFTP */
+#endif /* TCPSOCKET */
+
+#ifndef NOFRILLS
+case XXPRI:
+#ifdef UNIX
+    return(hmsg("Syntax: PRINT file [ options ]\n\
+  Prints the local file on a local printer with the given options.  Also see\n\
+  HELP SET PRINTER."));
+#else
+#ifdef VMS
+    return(hmsg("Syntax: PRINT file [ options ]\n\
+  Prints the local file on a local printer with the given options.  Also see\n\
+  HELP SET PRINTER."));
+#else
+    return(hmsg("Syntax: PRINT file\n\
+  Prints the local file on a local printer.  Also see HELP SET PRINTER."));
+#endif /* UNIX */
+#endif /* VMS */
+#endif /* NOFRILLS */
+
+case XXPWD:
+case XXLPWD:
+    return(hmsg("Syntax: PWD\n\
+Print the name of the current working directory."));
+
+#ifndef NOSPL
+case XXREA:
+    return(hmsg("Syntax: READ variablename\n\
+  Reads a line from the currently open READ or !READ file into the variable\n\
+  (see OPEN)."));
+#endif /* NOSPL */
+
+#ifndef NOXFER
+case XXREC:
+    return(hmsga(hmxxrc));
+
+case XXREM:
+    y = cmkey(remcmd,nrmt,"Remote command","",xxstring);
+    return(dohrmt(y));
+#endif /* NOXFER */
+
+#ifndef NOSPL
+case XXRET:
+    return(hmsg("Syntax: RETURN [ value ]\n\
+  Return from a macro.  An optional return value can be given for use with\n\
+  \\fexecute(macro), which allows macros to be used like functions."));
+#endif /* NOSPL */
+
+#ifndef NOXFER
+case XXSEN:
+    return(hmsga(hmxxsen));
+case XXMOVE:
+    return(hmsg("MOVE is exactly like SEND, except each file that is\n\
+sent successfully is deleted after it is sent."));
+#ifndef NORESEND
+case XXRSEN:
+    return(hmsg(hmxxrsen));
+case XXREGET:
+    return(hmsg(hmxxrget));
+case XXPSEN:
+    return(hmsg(hmxxpsen));
+#endif /* NORESEND */
+
+#ifndef NOSERVER
+case XXSER:
+    return(hmsg(hmxxser));
+#endif /* NOSERVER */
+#endif /* NOXFER */
+
+#ifndef NOJC
+case XXSUS:
+    return(hmsg("Syntax: SUSPEND or Z\n\
+  Suspends Kermit.  Continue Kermit with the appropriate system command,\n\
+  such as fg."));
+#endif /* NOJC */
+
+case XXSET:
+    y = cmkey(prmtab,nprm,"Parameter","",xxstring);
+    debug(F101,"HELP SET y","",y);
+    return(dohset(y));
+
+#ifndef NOPUSH
+case XXSHE:
+    if (nopush) {
+        if ((x = cmcfm()) < 0) return(x);
+        printf("Sorry, help not available for \"%s\"\n",cmdbuf);
+        break;
+    } else
+       return(hmsga(hxxshe));
+#ifdef CK_REDIR
+case XXFUN:
+    return(hmsg("Syntax: REDIRECT command\n\
+  Runs the given local command with its standard input and output redirected\n\
+  to the current SET LINE or SET HOST communications path.\n\
+  Synonym: < (Left angle bracket)."));
+#endif /* CK_REDIR */
+
+#ifdef CK_REXX
+case XXREXX:
+    return(hmsg("Syntax: REXX text\n\
+  The text is a Rexx command to be executed. The \\v(rexx) variable is set\n\
+  to the Rexx command's return value.\n\
+  To execute a rexx program file, use:  REXX call <filename>\n\
+  Rexx programs may call Kermit functions by placing the Kermit command\n\
+  in single quotes.  For instance:  'set parity none'."));
+#endif /* CK_REXX */
+#endif /* NOPUSH */
+
+#ifndef NOSHOW
+case XXSHO:
+    return(hmsg("\
+  Display current values of various items (SET parameters, variables, etc).\n\
+  Type SHOW ? for a list of categories."));
+#endif /* NOSHOW */
+
+case XXSPA:
+#ifdef datageneral
+    return(hmsg("\
+  Display disk usage in current device, directory,\n\
+  or return space for a specified device, directory."));
+#else
+    return(hmsg("Syntax: SPACE\n\
+  Display disk usage in current device and/or directory"));
+#endif
+
+case XXSTA:
+    return(hmsg("Syntax: STATISTICS [/BRIEF]\n\
+  Display statistics about most recent file transfer"));
+
+#ifndef NOSPL
+case XXSTO:
+    return(hmsg("Syntax: STOP [ number [ message ] ]\n\
+  Stop executing the current macro or TAKE file and return immediately to\n\
+  the Kermit prompt.  Number is a return code.  Message printed if given."));
+#endif /* NOSPL */
+
+case XXTAK:
+    return(hmsga(hmxxtak));
+
+#ifdef TCPSOCKET
+#ifdef TNCODE
+case XXIKSD:
+    return(hmsga(hmxxiks));
+
+case XXTEL:
+    return(hmsga(hmxxtel));
+
+case XXTELOP:
+    return(hmsga(hxtopt));
+#endif /* TNCODE */
+
+#ifdef RLOGCODE
+case XXRLOG:
+    return(hmsg("Syntax: RLOGIN [ switches ] [ host [ username ] ]\n\
+  Equivalent to SET NETWORK TYPE TCP/IP, SET HOST host [ service ] /RLOGIN,\n\
+  IF SUCCESS CONNECT.  If host is omitted, the previous connection (if any)\n\
+  is resumed.  Depending on how Kermit has been built switches may be\n\
+  available to require Kerberos authentication and DES encryption."));
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+
+#ifndef NOXMIT
+case XXTRA:
+    return(hmsga(hxxxmit));
+#endif /* NOXMIT */
+
+#ifndef NOFRILLS
+case XXTYP:
+    return(hmsga(hmxxtyp));
+case XXMORE:
+    return(hmsg("Syntax: MORE [ switches ] filename\n\
+  Equivalent to TYPE /PAGE filename; see HELP TYPE."));
+case XXCAT:
+    return(hmsg("Syntax: MORE [ switches ] filename\n\
+  Equivalent to TYPE /NOPAGE filename; see HELP TYPE."));
+case XXHEAD:
+    return(hmsg("Syntax: HEAD [ switches ] filename\n\
+  Equivalent to TYPE /HEAD filename; see HELP TYPE."));
+case XXTAIL:
+    return(hmsg("Syntax: TAIL [ switches ] filename\n\
+  Equivalent to TYPE /TAIL filename; see HELP TYPE."));
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+case XXWHI:
+    return(hmsga(whihlp));
+
+case XXSWIT:
+    return(hmsga(swihlp));
+#endif /* NOSPL */
+
+#ifndef NOCSETS
+case XXXLA:
+    return(hmsga(hxxxla));
+#endif /* NOCSETS */
+
+case XXVER:
+    return(hmsg("Syntax: VERSION\nDisplays the program version number."));
+
+#ifndef NOSPL
+case XXWAI:
+    return(hmsga(hxxwai));
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+case XXWHO:
+    return(hmsg("Syntax: WHO [ user ]\nDisplays info about the user."));
+
+case XXWRI:
+    return(hmsga(hxxwri));
+
+case XXWRL:
+    return(hmsg(
+"WRITE-LINE (WRITELN) is just like WRITE, but includes a line terminator\n\
+at the end of text.  See WRITE."));
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+case XXIFX:
+    return(hmsga(ifxhlp));
+
+case XXGETC:                            /* GETC */
+    return(hmsga(hxxgetc));
+
+case XXFWD:                             /* FORWARD */
+    return(hmsg(
+"Like GOTO, but searches only forward for the label.  See GOTO."));
+
+case XXLOCAL:                           /* LOCAL */
+    return(hmsg(
+"Declares a variable to be local to the current macro or command file."));
+#endif /* NOSPL */
+
+case XXVIEW:
+    return(hmsg(
+"View the terminal emulation screen even when there is no connection."));
+
+case XXASC:
+    return(hmsg("Synonym for SET FILE TYPE TEXT."));
+
+case XXBIN:
+    return(hmsg("Synonym for SET FILE TYPE BINARY."));
+
+case XXDATE:
+    return(hmsga(hmxxdate));
+
+case XXRETR:
+    return(hmsg(
+"Just like GET but asks the server to delete each file that has been\n\
+sent successfully."));
+
+case XXEIGHT:
+    return(hmsg(
+"Equivalent to SET PARITY NONE, SET COMMAND BYTE 8, SET TERMINAL BYTE 8."));
+
+case XXSAVE:
+    return(hmsga(hmxxsave));
+
+#ifndef NOFRILLS
+#ifndef NOPUSH
+case XXEDIT:
+    return(hmsg("Syntax: EDIT [ <file> ]\n\
+Starts your preferred editor on the given file, or if none given, the most\n\
+recently edited file, if any.  Also see SET EDITOR."));
+#endif /* NOPUSH */
+#endif /* NOFRILLS */
+
+#ifdef BROWSER
+case XXBROWS:
+    return(hmsg("Syntax: BROWSE [ <url> ]\n\
+Starts your preferred Web browser on the given URL, or if none given, the\n\
+most recently visited URL, if any.  Also see SET BROWSER."));
+#endif /* BROWSER */
+
+#ifdef CK_TAPI
+case XXTAPI:
+    return(hmsga(hxxtapi));
+#endif /* CK_TAPI */
+
+#ifdef PIPESEND
+case XXCSEN:
+    return(hmsg("Syntax: CSEND [ switches ] <command> [ <as-name> ]\n\
+Sends from the given <command> rather than from a file.  Equivalent to\n\
+SEND /COMMAND; see HELP SEND for details."));
+
+case XXCREC:
+    return(hmsg("Syntax: CRECEIVE [ switches ] <command>\n\
+Receives to the given <command> rather than to a file.  Equivalent to\n\
+RECEIVE /COMMAND; see HELP RECEIVE for details."));
+
+case XXCGET:
+    return(hmsg("Syntax: CGET <remote-file-or-command> <local-command>\n\
+Equivalent to GET /COMMAND; see HELP GET for details."));
+#endif /* PIPESEND */
+
+#ifndef NOSPL
+case XXFUNC:
+/*
+  Tricky parsing.  We want to let them type the function name in any format
+  at all: \fblah(), \fblah, \\fblah(), fblah, blah, blah(), etc, but of course
+  only one of these is recognized by cmkey().  So we call cmkeyx() (the "no
+  complaints" version of cmkey()), and if it fails, we try the other formats
+  silently, and still allow for <no-name-given>, editing and reparse, etc.
+*/
+    y = cmkeyx(fnctab,nfuncs,"Name of function","",NULL);
+    if (y == -1) {                      /* Reparse needed */
+        return(y);
+    } else if (y == -3) {
+        if ((x = cmcfm()) < 0)          /* For recall buffer... */
+          return(x);
+        return(dohfunc(y));             /* -3 gives general message */
+    }
+    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 */
+    }
+    if (y < 0) {
+        printf("?No such function - \"%s\"\n",atmbuf);
+        return(-9);
+    }
+    x = cmgbrk();                       /* Find out how user terminated */
+    if (x == LF || x == CR)             /* if with CR or LF */
+      cmflgs = 1;                       /* restore cmflgs to say so */
+    if ((x = cmcfm()) < 0)              /* And THEN confirm so command will */
+      return(x);                        /* get into recall buffer. */
+    return(dohfunc(y));
+#endif /* NOSPL */
+
+#ifndef NOCMDL
+case XXOPTS:                            /* Command-line options */
+    return(dohopts());
+
+case XXXOPTS:                           /* Extended command-line options */
+    return(doxopts());
+#endif /* NOCMDL */
+
+#ifdef OS2
+#ifndef NOKVERBS
+case XXKVRB: {
+    y = cmkeyx(kverbs,nkverbs,"Name of keyboard verb without \\k","",NULL);
+    if (y == -1) {                      /* Reparse needed */
+        return(y);
+    } else if (y == -3) {
+        if ((x = cmcfm()) < 0)          /* For recall buffer... */
+          return(x);
+        return(dohkverb(y));            /* -3 gives general message */
+    }
+    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 "\\k" or "\k" or "k" */
+        p = atmbuf;
+        if (*p == CMDQ)                 /* Allow for \\k... */
+          p++;
+        if (*p == CMDQ && (*(p+1) == 'k' || *(p+1) == 'K')) { /* or \k */
+            p += 2;
+        } else if (*p == 'k' || *p == 'K') { /* or just k */
+            p++;
+        }
+        y = lookup(kverbs,p,nkverbs,&dummy); /* Look up the result */
+    }
+    if (y < 0) {
+        printf("?No such function - \"%s\"\n",atmbuf);
+        return(-9);
+    }
+    x = cmgbrk();                       /* Find out how user terminated */
+    if (x == LF || x == CR)             /* if with CR or LF */
+      cmflgs = 1;                       /* restore cmflgs to say so */
+    if ((x = cmcfm()) < 0)              /* And THEN confirm so command will */
+      return(x);                        /* get into recall buffer. */
+    return(dohkverb(y));
+}
+#endif /* NOKVERBS */
+#endif /* OS2 */
+
+case XXKERMI:
+    return(hmsg("Syntax: KERMIT [command-line-options]\n\
+  Lets you give command-line options at the prompt or in a script.\n\
+  HELP OPTIONS for more info."));
+
+case XXBACK:
+    return(hmsg("Syntax: BACK\n  Returns to your previous directory."));
+
+case XXWHERE:
+    return(hmsg("Syntax: WHERE\n  Tells where your transferred files went."));
+
+#ifndef NOXFER
+case XXREMV:
+    return(hmsga(hmxxremv));
+#endif /* NOXFER */
+
+#ifdef CK_KERBEROS
+case XXAUTH:
+    return(hmsga(hmxxauth));
+#endif /* CK_KERBEROS */
+
+#ifndef NOHTTP
+case XXHTTP:
+    return(hmsga(hmxxhttp));
+#endif /* NOHTTP */
+
+#ifdef NETCMD
+case XXPIPE:
+    return(hmsg("Syntax: PIPE [ command ]\n\
+Makes a connection through the program whose command line is given. Example:\n\
+\n pipe rlogin xyzcorp.com"));
+#endif /* NETCMD */
+
+case XXSTATUS:
+    return(hmsg(
+"STATUS is the same as SHOW STATUS; prints SUCCESS or FAILURE for the\n\
+previous command."));
+
+#ifndef NOSPL
+case XXASSER:
+    return(hmsg("Syntax: ASSERT <condition>\n\
+Succeeds or fails depending on <condition>; see HELP IF for <condition>s."));
+
+case XXFAIL:
+    return(hmsg("Always fails."));
+
+case XXSUCC:
+    return(hmsg("Always succeeds."));
+#endif /* NOSPL */
+
+#ifdef CK_LOGIN
+case XXLOGOUT:
+    return(hmsg(
+"If you haved logged in to Kermit as an Internet Kermit server, the LOGOUT\n\
+command, given at the prompt, logs you out and closes your session."));
+#endif /* CK_LOGIN */
+
+case XXRESET:
+    return(hmsg("Closes all open files and logs."));
+
+#ifndef NOCSETS
+case XXASSOC:
+    return(hmsga(hmxxassoc));
+#endif /* NOCSETS */
+
+#ifndef NOSPL
+case XXSHIFT:
+    return(hmsg("Syntax: SHIFT [ n ]\n\
+  Shifts \\%1..9 variables n places to the left; default n = 1."));
+#endif /* NOSPL */
+
+#ifndef NOPUSH
+case XXMAN:
+#ifdef UNIX
+    return(hmsg("Syntax: MANUAL [ topic ]\n\
+  Runs the \"man\" command on the given topic (default \"kermit\")."));
+#else
+#ifdef OS2
+    return(hmsg("Syntax: MANUAL\n\
+  Accesses the Kermit 95 HTML manual using the current browser."));
+#else
+    return(hmsg("Syntax: MANUAL [ topic ]\n\
+  Runs the \"help\" command on the given topic (default \"kermit\")."));
+#endif /* OS2 */
+#endif /* UNIX */
+#endif /* NOPUSH */
+
+case XXWILD:
+    return(hmsga(hmxxwild));
+
+case XXPAT:
+    return(hmsga(hmxxpat));
+
+#ifndef NOXFER
+case XXFAST:
+case XXCAU:
+case XXROB:
+    return(hmsga(hmxxfast));
+#endif /* NOXFER */
+
+#ifdef CKPURGE
+case XXPURGE:
+    return(hmsga(hmxxpurge));
+#else
+#ifdef VMS
+case XXPURGE:
+    return(hmsga(hmxxpurge));
+#endif /* VMS */
+#endif /* CKPURGE */
+
+#ifndef NOXFER
+  case XXRASG:
+    return(hmsg("  RASG and RASSIGN are short forms of REMOTE ASSIGN."));
+  case XXRCWD:
+    return(hmsg("  RCD and RCWD are short forms of REMOTE CD."));
+  case XXRCPY:
+    return(hmsg("  RCOPY is a short form of REMOTE COPY."));
+  case XXRDEL:
+    return(hmsg("  RDELETE is a short form of REMOTE RELETE."));
+  case XXRDIR:
+    return(hmsg("  RDIRECTORY is a short form of REMOTE DIRECTORY."));
+  case XXRXIT:
+    return(hmsg("  REXIT is a short form of REMOTE EXIT."));
+  case XXRHLP:
+    return(hmsg("  RHELP is a short form of REMOTE HELP."));
+  case XXRHOS:
+    return(hmsg("  RHOST is a short form of REMOTE HOST."));
+  case XXRKER:
+    return(hmsg("  RKERMIT is a short form of REMOTE KERMIT."));
+  case XXRMKD:
+    return(hmsg("  RMKDIR is a short form of REMOTE MKDIR."));
+  case XXRPRI:
+    return(hmsg("  RPRINT is a short form of REMOTE PRINT."));
+  case XXRPWD:
+    return(hmsg("  RPWD is a short form of REMOTE PWD."));
+  case XXRQUE:
+    return(hmsg("  QUERY and RQUERY are short forms of REMOTE QUERY."));
+  case XXRREN:
+    return(hmsg("  RRENAME is a short form of REMOTE RENAME."));
+  case XXRRMD:
+    return(hmsg("  RRMDIR is a short form of REMOTE RMDIR."));
+  case XXRSET:
+    return(hmsg("  RSET is a short form of REMOTE SET."));
+  case XXRSPA:
+    return(hmsg("  RSPACE is a short form of REMOTE SPACE."));
+  case XXRTYP:
+    return(hmsg("  RTYPE is a short form of REMOTE TYPE."));
+  case XXRWHO:
+    return(hmsg("  RWHO is a short form of REMOTE WHO."));
+#endif /* NOXFER */
+
+  case XXSCRN:
+    return(hmsga(hmxxscrn));
+
+#ifdef CKEXEC
+  case XXEXEC:
+    return(hmsg("Syntax: EXEC <command> [ <arg1> [ <arg2> [ ... ] ]\n\
+  C-Kermit overlays itself with the given system command and starts it with\n\
+  the given arguments.  Upon any error, control returns to C-Kermit."));
+#endif /* CKEXEC */
+
+#ifndef NOSPL
+  case XXTRACE:
+    return(hmsg(
+"Syntax: TRACE { /ON, /OFF } { ASSIGNMENTS, COMMAND-LEVEL, ALL }\n\
+  Turns tracing of the given object on or off."));
+#endif /* NOSPL */
+
+#ifdef CK_PERMS
+#ifdef UNIX
+  case XXCHMOD:
+    return(hmsga(hmxxchmod));
+#endif /* UNIX */
+#endif /* CK_PERMS */
+
+#ifdef CKROOT
+  case XXCHRT:
+    return(hmsga(hmxxchroot));
+#endif /* CKROOT */
+
+#ifndef NOSPL
+  case XXPROMP:
+    return(hmsga(hmxxprompt));
+#endif /* NOSPL */
+
+  case XXGREP:
+    return(hmsga(hmxxgrep));
+
+#ifndef NOSEXP
+#ifndef NOSPL
+  case XXSEXP:
+    return(hmsga(hmxxsexp));
+#endif /* NOSPL */
+#endif /* NOSEXP */
+
+#ifdef CKLEARN
+  case XXLEARN:
+    return(hmsga(hmxxlearn));
+#endif /* CKLEARN */
+
+#ifdef ANYSSH
+  case XXSSH:
+    return(hmsga(hmxxssh));
+#endif /* ANYSSH */
+
+#ifdef TCPSOCKET
+  case XXFIREW:
+    return(hmsga(hmxxfirew));
+#endif /* TCPSOCKET */
+
+#ifdef NEWFTP
+  case XXUSER:
+    return(hmsg(" Equivalent to FTP USER."));
+  case XXACCT:
+    return(hmsg(" Equivalent to FTP ACCOUNT."));
+#endif /* NEWFTP */
+
+  case XXORIE:
+    return(hmsg(" Shows the directories important to Kermit."));
+
+  case XXCONT:
+    return(hmsg(" In a FOR or WHILE loop: continue the loop.\n\
+ At the prompt: continue a script that has \"shelled out\" to the prompt."));
+
+  case XXNOTAV:
+    return(hmsg(" This command is not configured in this version of Kermit."));
+
+default: {
+        char *s;
+        if ((x = cmcfm()) < 0) return(x);
+        s = cmdbuf + (int)strlen(cmdbuf) -1;
+        while (s >= cmdbuf && *s == SP)
+          *s-- = NUL;
+        while (s >= cmdbuf && *s != SP)
+          s--;
+        while (*s == SP) s++;
+        printf("Sorry, help not available for \"%s\"\n",s);
+        break;
+      }
+    } /* switch */
+#endif /* NOHELP */
+
+    return(success = 0);
+}
+
+/*  H M S G  --  Get confirmation, then print the given message  */
+
+int
+hmsg(s) char *s; {
+    int x;
+    if ((x = cmcfm()) < 0) return(x);
+    printf("\n%s\n\n",s);
+    return(0);
+}
+
+#ifdef NOHELP
+
+int                                     /* Print an array of lines, */
+hmsga(s) char *s[]; {                   /* cheap version. */
+    int i;
+    if ((i = cmcfm()) < 0) return(i);
+    printf("\n");                       /* Start off with a blank line */
+    for (i = 0; *s[i]; i++) {           /* Print each line. */
+        printf("%s\n",s[i]);
+    }
+    printf("\n");
+    return(0);
+}
+
+#else /* NOHELP not defined... */
+
+int                                     /* Print an array of lines, */
+hmsga(s) char *s[]; {                   /* pausing at end of each screen. */
+    extern int hmtopline;               /* (This should be a parameter...) */
+    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("%s\n",s[i]);            /* Print a line. */
+        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);
+}
+
+#ifndef NOXMIT
+static char *hsetxmit[] = {
+"Syntax: SET TRANSMIT parameter value",
+" ",
+"Controls the behavior of the TRANSMIT command (see HELP TRANSMIT):",
+" ",
+"SET TRANSMIT ECHO { ON, OFF }",
+"  Whether to echo text to your screen as it is being transmitted.",
+" ",
+"SET TRANSMIT EOF text",
+"  Text to send after end of file is reached, e.g. \\4 for Ctrl-D",
+" ",
+"SET TRANSMIT FILL number",
+"  ASCII value of a character to insert into blank lines, 0 for none.",
+"  Applies only to text mode.  0 by default.",
+" ",
+"SET TRANSMIT LINEFEED { ON, OFF }",
+"  Transmit Linefeed as well as Carriage Return (CR) at the end of each line.",
+"  Normally, only CR  is sent.",
+" ",
+"SET TRANSMIT LOCKING-SHIFT { ON, OFF }",
+"  Whether to use SO/SI for transmitting 8-bit data when PARITY is not NONE.",
+" ",
+"SET TRANSMIT PAUSE number",
+"  How many milliseconds to pause after transmitting each line (text mode),",
+"  or each character (binary mode).",
+" ",
+"SET TRANSMIT PROMPT number",
+"  ASCII value of character to look for from host before sending next line",
+"  when TRANSMITting in text mode; normally 10 (Linefeed).  0 means none;",
+"  don't wait for a prompt.",
+" ",
+"SET TRANSMIT TIMEOUT number",
+"  Number of seconds to wait for each character to echo when TRANSMIT ECHO",
+"  is ON or TRANSMIT PROMPT is not 0.  If 0 is specified, this means wait",
+"  indefinitely for each echo.",
+" ",
+"Synonym: SET XMIT.  SHOW TRANSMIT displays current settings.",
+"" };
+#endif /* NOXMIT */
+
+static char *hsetbkg[] = {
+"Syntax: SET BACKGROUND { OFF, ON }",
+" ",
+"  SET BACKGROUND OFF forces prompts and messages to appear on your screen",
+"  even though Kermit thinks it is running in the background.",
+"" };
+
+#ifdef DYNAMIC
+static char *hsetbuf[] = {
+"Syntax: SET BUFFERS n1 [ n2 ]",
+" ",
+"  Changes the overall amount of memory allocated for SEND and RECEIVE packet",
+"  buffers, respectively.  Bigger numbers let you have longer packets and",
+"  more window slots.  If n2 is omitted, the same value as n1 is used.",
+#ifdef BIGBUFOK
+" ",
+"  NOTE: This command is not needed in this version of Kermit, which is",
+"  already configured for maximum-size packet buffers.",
+#endif /* BIGBUFOK */
+"" };
+#endif /* DYNAMIC */
+
+static char *hsetcmd[] = {
+"Syntax: SET COMMAND parameter value",
+" ",
+
+#ifdef CK_AUTODL
+"SET COMMAND AUTODOWNLOAD { ON, OFF }",
+"  Enables/Disables automatic recognition of Kermit packets while in",
+"  command mode.  ON by default.",
+" ",
+#endif /* CK_AUTODL */
+
+"SET COMMAND BYTESIZE { 7, 8 }",
+"  Informs Kermit of the bytesize of the communication path between itself",
+"  and your keyboard and screen.  8 is assumed.  SET COMMAND BYTE 7 only if",
+"  8-bit characters cannot pass.",
+" ",
+
+#ifdef OS2
+"SET COMMAND COLOR <foreground-color> <background-color>",
+"  Lets you choose colors for Command screen.  Use ? in the color fields to",
+"  to get lists of available colors.",
+" ",
+"SET COMMAND CURSOR-POSITION <row> <column>",
+"  Moves the command-screen cursor to the given position (1-based).  This",
+"  command should be used in scripts instead of relying on ANSI.SYS escape",
+"  sequences.",
+" ",
+#endif /* OS2 */
+
+#ifdef OS2
+#ifdef NT
+"SET COMMAND HEIGHT <number>",
+"  Changes the number of rows (lines) in your command screen, not",
+"  counting the status line.  Recommended values are 24, 42, and 49 (or 25,",
+"  43, and 50 if SET COMMAND STATUSLINE is OFF.)",
+#else
+"SET COMMAND HEIGHT <number>"
+"  Changes the number of rows (lines) in your command screen, not",
+"  counting the status line.  Windowed sessions can use any value from 8 to",
+"  101.  Fullscreen sessions are limited to 24, 42, 49, or 59.  Not all"
+"  heights are supported by all video adapters.",
+#endif /* NT */
+#else  /* OS2 */
+"SET COMMAND HEIGHT <number>",
+"  Informs Kermit of the number of rows in your command screen for the",
+"  purposes of More?-prompting.",
+#endif /* OS2 */
+" ",
+"SET COMMAND WIDTH <number>",
+"  Informs Kermit of the number of characters across your screen for",
+"  purposes of screen formatting.",
+" ",
+"SET COMMAND MORE-PROMPTING { ON, OFF }",
+"  ON (the default) enables More?-prompting when Kermit needs to display",
+"  text that does not fit vertically on your screen.  OFF allows the text to",
+"  scroll by without intervention.  If your command window has scroll bars,",
+"  you might prefer OFF.",
+" ",
+
+#ifdef CK_RECALL
+"SET COMMAND RECALL-BUFFER-SIZE number",
+"  How big you want Kermit's command recall buffer to be.  By default, it",
+"  holds 10 commands.  You can make it any size you like, subject to memory",
+"  constraints of the computer.  A size of 0 disables command recall.",
+"  Whenever you give this command, previous command history is lost.",
+" ",
+#endif /* CK_RECALL */
+
+"SET COMMAND QUOTING { ON, OFF }",
+"  Whether to treat backslash and question mark as special characters (ON),",
+"  or as ordinary data characters (OFF) in commands.  ON by default.",
+" ",
+#ifdef DOUBLEQUOTING
+"SET COMMAND DOUBLEQUOTING { ON, OFF }",
+"  Whether to allow doublequotes (\") to be used to enclose fields,",
+"  filenames, directory names, and macro arguments that might contain",
+"  spaces.  ON by default; use OFF to force compatibility with older",
+"  versions.",
+" ",
+#endif /* DOUBLEQUOTING */
+
+#ifdef CK_RECALL
+"SET COMMAND RETRY { ON, OFF }",
+"  Whether to reprompt you with the correct but incomplete portion of a",
+"  syntactically incorrect command.  ON by default.",
+" ",
+#endif /* CK_RECALL */
+
+#ifdef OS2
+"SET COMMAND SCROLLBACK <lines>",
+"  Sets size of virtual Command screen buffer to the given number of lines,",
+"  which includes the active Command screen.  The minimum is 256.  The max",
+"  is 2 million.  The default is 512.",
+" ",
+"SET COMMAND STATUSLINE { ON, OFF }",
+"  ON (default) enables the Kermit status line in the command screen.",
+"  OFF removes it, making the line available for use by the host.",
+" ",
+#endif /* OS2 */
+
+"Use SHOW COMMAND to display these settings.",
+"" };
+
+#ifndef NOLOCAL
+static char *hsetcar[] = {
+"Syntax: SET CARRIER-WATCH { AUTO, OFF, ON }",
+" ",
+"  Attempts to control treatment of carrier (the Data Carrier Detect signal)",
+"  on serial communication (SET LINE or SET PORT) devices.  ON means that",
+"  carrier is required at all times.  OFF means carrier is never required.",
+"  AUTO (the default) means carrier is required at all times except during",
+"  the DIAL command.  Correct operation of carrier-watch depends on the",
+"  capabilities of the underlying OS, drivers, devices, and cables.  If you",
+"  need to CONNECT to a serial device that is not asserting carrier, and",
+"  Kermit won't let you, use SET CARRIER-WATCH OFF.  Use SHOW COMMUNICATIONS",
+"  to display the CARRIER-WATCH setting.",
+"" };
+#endif /* NOLOCAL */
+
+static char *hsetat[] = {
+"Syntax: SET ATTRIBUTES name ON or OFF",
+" ",
+"  Use this command to enable (ON) or disable (OFF) the transmission of",
+"  selected file attributes along with each file, and to handle or ignore",
+"  selected incoming file attributes, including:",
+" ",
+#ifndef NOCSETS
+"   CHARACTER-SET:  The transfer character set for text files",
+#endif /* NOCSETS */
+"   DATE:           The file's creation date",
+"   DISPOSITION:    Unusual things to do with the file, like MAIL or PRINT",
+"   LENGTH:         The file's length",
+"   PROTECTION:     The file's protection (permissions)",
+"   SYSTEM-ID:      Machine/Operating system of origin",
+"   TYPE:           The file's type (text or binary)",
+" ",
+"You can also specify ALL to select all of them.  Examples:",
+" ",
+"   SET ATTR DATE OFF",
+"   SET ATTR LENGTH ON",
+"   SET ATTR ALL OFF",
+" ",
+"Also see HELP SET SEND and HELP SET RECEIVE.",
+""
+};
+
+static char *hxytak[] = {
+"Syntax: SET TAKE parameter value",
+" ",
+"  Controls behavior of TAKE command:",
+" ",
+"SET TAKE ECHO { ON, OFF }",
+"  Tells whether commands read from a TAKE file should be displayed on the",
+"  screen (if so, each command is shown at the time it is read, and labeled",
+"  with a line number).",
+" ",
+"SET TAKE ERROR { ON, OFF }",
+"  Tells whether a TAKE command file should be automatically terminated when",
+"  a command fails.  This setting is local to the current command file, and",
+"  inherited by subordinate command files.",
+"" };
+
+#ifndef NOLOCAL
+#ifdef OS2MOUSE
+static char *hxymouse[] = {
+"Syntax: SET MOUSE ACTIVATE { ON, OFF }",
+"  Enables or disables the mouse in Connect mode.  Default is ON",
+" ",
+"Syntax: SET MOUSE BUTTON <number> <key-modifier> <action> [ <text> ]",
+" where:",
+"  <number> is the mouse button number, 1, 2, or 3;",
+"  <key-modifier> denotes modifier keys held down during the mouse event:",
+"   ALT, ALT-SHIFT, CTRL, CTRL-ALT CTRL-ALT-SHIFT, CTRL-SHIFT, SHIFT, NONE;",
+"  <action> is the mouse action, CLICK, DRAG, or DOUBLE-CLICK.",
+" ",
+" The <text> has exactly the same properties as the <text> from the SET KEY",
+" command -- it can be a character, a string, one or more Kverbs, a macro",
+" invoked as a Kverb, or any combination of these.  Thus, anything that can",
+" be assigned to a key can also be assigned to the mouse -- and vice versa.",
+" If the <text> is omitted, the action will be ignored.  Examples:",
+" ",
+" SET MOUSE BUTTON 1 NONE DOUBLE \\KmouseCurPos",
+" SET MOU B 2 SHIFT CLICK help\\13",
+" ",
+" DRAG operations perform a \"mark mode\" selection of Text. You should",
+" assign only the following actions to drag operations:",
+" ",
+"  \\Kdump         - copy marked text to printer (or file)",
+"  \\Kmarkcopyclip - copy marked text to PM Clipboard",
+"  \\Kmarkcopyhost - copy marked text direct to Host",
+"  \\Kmousemark    - mark text, no copy operation performed",
+" ",
+" The following Kverb is only for use with the mouse:",
+" ",
+"  \\KmouseCurPos",
+" ",
+" which represents the mouse-directed terminal cursor feature.",
+" ",
+"Syntax: SET MOUSE CLEAR",
+" Restores all mouse events to their default definitions",
+"   Button 1 Ctrl-Click = Kverb: \\Kmouseurl",
+"   Button 1 Double-Click = Kverb: \\Kmousecurpos",
+"   Button 1 Drag = Kverb: \\Kmarkcopyclip",
+"   Button 1 Alt-Drag = Kverb: \\Kmarkcopyclip_noeol",
+"   Button 1 Ctrl-Drag = Kverb: \\Kmarkcopyhost",
+"   Button 1 Ctrl-Alt-Drag = Kverb: \\Kmarkcopyhost_noeol",
+"   Button 1 Ctrl-Shift-Drag = Kverb: \\Kdump",
+"   Button 2 Double-Click = Kverb: \\Kpaste",
+"   Button 2 Drag = Kverb: \\Kmarkcopyhost",
+"   Button 2 Alt-Drag = Kverb: \\Kmarkcopyhost_noeol     ",    
+"   Button 3 Double-Click = Kverb: \\Kpaste",
+""};
+#endif /* OS2MOUSE */
+
+static char *hxyterm[] = {
+"Syntax: SET TERMINAL parameter value",
+" ",
+#ifdef OS2
+"SET TERMINAL TYPE { ANSI, VT52, VT100, VT102, VT220, VT320, ... }",
+"  Selects type type of terminal to emulate.  Type SET TERMINAL TYPE ? to",
+"  see a complete list.",
+" ",
+"SET TERMINAL ANSWERBACK { OFF, ON }",
+"  Disables/enables the ENQ/Answerback sequence (\"K-95 version term-type\").",
+" ",
+"SET TERMINAL ANSWERBACK MESSAGE <extension>",
+"  Allows you to specify an extension to the default answerback message.",
+" ",
+#else
+"SET TERMINAL TYPE ...",
+"  This command is not available because this version of Kermit does not",
+"  include a terminal emulator.  Instead, it is a \"semitransparent pipe\"",
+"  (or a totally transparent one, if you configure it that way) to the",
+"  computer or service you have made a connection to.  Your console,",
+"  workstation window, or the terminal emulator or terminal from which you",
+"  are running Kermit provides the emulation.",
+" ",
+#endif /* OS2 */
+
+#ifdef CK_APC
+"SET TERMINAL APC { ON, OFF, NO-INPUT, NO-INPUT-UNCHECKED, UNCHECKED }",
+#ifdef OS2
+"  Controls execution of Application Program Commands sent by the host while",
+"  K-95 is either in CONNECT mode or processing INPUT commands.  ON allows",
+"  execution of \"safe\" commands and disallows potentially dangerous ones",
+"  such as DELETE, RENAME, OUTPUT, and RUN.  OFF prevents execution of APCs.",
+"  UNCHECKED allows execution of all APCs.  OFF is the default.",
+#else /* OS2 */
+"  Controls execution of Application Program Commands sent by the host while",
+"  C-Kermit is in CONNECT mode.  ON allows execution of \"safe\" commands and",
+"  disallows potentially dangerous commands such as DELETE, RENAME, OUTPUT,",
+"  and RUN.  OFF prevents execution of APCs.  UNCHECKED allows execution of",
+"  all APCs.  OFF is the default.",
+#endif /* OS2 */
+" ",
+#endif /* CK_APC */
+
+#ifdef OS2
+"SET TERMINAL ARROW-KEYS { APPLICATION, CURSOR }",
+"  Sets the mode for the arrow keys during VT terminal emulation.",
+" ",
+"SET TERMINAL ATTRIBUTE { BLINK, DIM, PROTECTED, REVERSE, UNDERLINE }",
+"  Determines how attributes are displayed by Kermit-95.",
+" ",
+"SET TERMINAL ATTRIBUTE { BLINK, DIM, REVERSE, UNDERLINE } { ON, OFF }",
+"  Determines whether real Blinking, Dim, Reverse, and Underline are used in",
+"  the terminal display.  When BLINK is turned OFF, reverse background",
+"  intensity is used.  When DIM is turned OFF, dim characters appear BOLD.",
+"  When REVERSE and UNDERLINE are OFF, the colors selected with SET",
+"  TERMINAL COLOR { REVERSE,UNDERLINE } are used instead.  This command",
+"  affects the entire current screen and terminal scrollback buffer.",
+" ",
+"SET TERMINAL ATTRIBUTE PROTECTED [ -",
+"   { BOLD, DIM, INVISIBLE, NORMAL, REVERSE, UNDERLINED } ]",
+"  Sets the attributes used to represent Protected text in Wyse and Televideo",
+"  terminal emulations.  Any combination of attributes may be used.  The",
+"  default is DIM.)",
+" ",
+#endif /* OS2 */
+
+#ifdef OS2
+#ifdef CK_XYZ
+"SET TERMINAL AUTODOWNLOAD { ON, OFF, ERROR { STOP, CONTINUE } }",
+"  enables/disables automatic switching into file-transfer mode when a Kermit",
+"  or ZMODEM file transfer has been detected during CONNECT mode or while",
+"  an INPUT command is active.  Default is OFF.",
+#else
+"SET TERMINAL AUTODOWNLOAD { ON, OFF, ERROR { STOP, CONTINUE } }",
+"  enables/disables automatic switching into file-transfer mode when a Kermit",
+"  file transfer has been detected during CONNECT mode or while an INPUT",
+"  command is active.  Default is OFF.",
+#endif /* CK_XYZ */
+
+" ",
+"  When TERMINAL AUTODOWNLOAD is ON, the TERMINAL AUTODOWNLOAD ERROR setting",
+"  tells what to do if an error occurs during a file transfer or other",
+"  protocol operation initiated by the terminal emulator: STOP (the default)",
+"  means to remain in command mode so you can see what happened; CONTINUE",
+"  means to resume the CONNECT session (e.g. so a far-end script can continue",
+"  its work).",
+" ",
+
+#ifdef CK_XYZ
+"SET TERM... AUTO... { KERMIT, ZMODEM } C0-CONFLICTS { IGNORED, PROCESSED }",
+"  Determines whether the active terminal emulator should process or ignore",
+"  C0 control characters which are also used for the specified file transfer",
+"  protocol.  Kermit by default uses ^A (SOH) and Zmodem uses ^X (CAN).",
+"  Default is PROCESSED.",
+" ",
+"SET TERM... AUTO... { KERMIT, ZMODEM } DETECTION-METHOD { PACKET, STRING }",
+"  Determines whether the specified file transfer protocol should be detected",
+"  by looking for valid packets or by identifying a specified text string.",
+"  Default is PACKET.",
+" ",
+"SET TERM... AUTO... { KERMIT, ZMODEM } STRING <text>",
+"  Lets you assign an autodownload detection string for use with the",
+"  specified file transfer protocol.",
+"  Default for Kermit is \"READY TO SEND...\", for Zmodem is \"rz\\{13}\".",
+" ",
+#else /* CK_XYZ */
+"SET TERM... AUTO... KERMIT C0-CONFLICTS { IGNORED, PROCESSED }",
+"  Determines whether the active terminal emulator should process or ignore",
+"  C0 control characters which are also used for the specified file transfer",
+"  protocol.  Kermit by default uses ^A <SOH>.  Default is PROCESSED.",
+" ",
+"SET TERM... AUTO... KERMIT DETECTION-METHOD { PACKET, STRING }",
+"  Determines whether the specified file transfer protocol should be detected",
+"  by looking for valid packets or by identifying a specified text string.",
+"  Default is PACKET.",
+" ",
+"SET TERM... AUTO... KERMIT STRING <text>",
+"  Lets you assign an autodownload detection string for use with the",
+"  specified file transfer protocol.  Default is \"READY TO SEND...\".",
+" ",
+#endif /* CK_XYZ */
+"SET TERMINAL AUTOPAGE { ON, OFF }",
+" ",
+"SET TERMINAL AUTOSCROLL { ON, OFF }",
+" ",
+#else /* OS2 */
+"SET TERMINAL AUTODOWNLOAD { ON, OFF, ERROR { STOP, CONTINUE } }",
+"  Enables/disables automatic switching into file-transfer mode when a valid",
+#ifdef CK_XYZ
+"  Kermit or ZMODEM packet of the appropriate type is received during CONNECT",
+"  mode.  Default is OFF.",
+#else
+"  Kermit packet of the appropriate type is received during CONNECT mode.",
+"  Default is OFF.",
+#endif /* CK_XYZ */
+
+" ",
+"  When TERMINAL AUTODOWNLOAD is ON, the TERMINAL AUTODOWNLOAD ERROR setting",
+"  tells what to do if an error occurs during a file transfer or other",
+"  protocol operation initiated by the terminal emulator: STOP (the default)",
+"  means to remain in command mode so you can see what happened; CONTINUE",
+"  means to resume the CONNECT session (e.g. so a far-end script can continue",
+"  its work).",
+" ",
+
+#endif /* OS2 */
+
+#ifdef OS2
+"SET TERMINAL BELL { AUDIBLE, VISIBLE, NONE }",
+"  Specifies how Control-G (bell) characters are handled.  AUDIBLE means",
+"  a beep is sounded; VISIBLE means the screen is flashed momentarily.",
+" ",
+"  (This command has been superseded by SET BELL.)",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL BYTESIZE { 7, 8 }",
+"  Use 7- or 8-bit characters between Kermit and the remote computer during",
+"  terminal sessions.  The default is 8.",
+" ",
+
+#ifndef NOCSETS
+#ifdef OS2
+"SET TERMINAL CHARACTER-SET <remote-cs>",
+"  Specifies the character set used by the remote host, <remote-cs>.",
+"  Equivalent to SET TERM REMOTE-CHARACTER-SET <remote-cs> ALL.  For more",
+"  control over the details, use SET TERM REMOTE-CHARACTER-SET and (in",
+"  non-GUI K95 versions) SET TERM LOCAL-CHARACTER-SET; these are explained",
+"  below.  The default TERMINAL CHARACTER-SET is LATIN1 (ISO 8859-1).",
+#else  /* not OS2 */
+"SET TERMINAL CHARACTER-SET <remote-cs> [ <local-cs> ]",
+"  Specifies the character set used by the remote host, <remote-cs>, and the",
+"  character set used by C-Kermit locally, <local-cs>.  If you don't specify",
+"  the local character set, the current FILE CHARACTER-SET is used.  When",
+"  you specify two different character sets, C-Kermit translates between them",
+"  during CONNECT.  By default, both character sets are TRANSPARENT, and",
+"  no translation is done.",
+#endif /* OS2 */
+" ",
+#endif /* NOCSETS */
+
+#ifdef OS2
+
+"SET TERMINAL CODE-PAGE <number>",
+"  Lets you change the PC code page.  Only works for code pages that are",
+"  successfully prepared in CONFIG.SYS.  Use SHOW TERMINAL to list the",
+"  current code page and the available code pages.",
+#ifdef OS2ONLY
+" ",
+"  Also see SET TERMINAL FONT if the desired code page in not available in",
+"  your version of OS/2.",
+#endif /* OS2ONLY */
+" ",
+
+#ifndef NT
+"SET TERMINAL COLOR BORDER <foreground>",
+#endif /* NT */
+"SET TERMINAL COLOR <screenpart> <foreground> <background>",
+" Sets the colors of the terminal emulation screen.",
+" <screenpart> may be any of the following:",
+"  DEBUG, HELP-TEXT, REVERSE, SELECTION, STATUS-LINE, TERMINAL-SCREEN, or",
+"  UNDERLINED-TEXT.",
+" <foreground> and <background> may be any of:",
+"  BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LGRAY, DGRAY, LBLUE,",
+"  LGREEN, LCYAN, LRED, LMAGENTA, YELLOW or WHITE.",
+" The L prefix for the color names means Light.",
+" ",
+
+"SET TERMINAL COLOR ERASE { CURRENT-COLOR, DEFAULT-COLOR }",
+"  Determines whether the current color as set by the host or the default",
+"  color as set by the user (SET TERMINAL COLOR TERMINAL) is used to clear",
+"  the screen when erase commands are received from the host.",
+" ",
+
+"SET TERMINAL COLOR RESET-ON-ESC[0m { CURRENT-COLOR, DEFAULT-COLOR }",
+"  Determines whether the current color or the default color is used after",
+"  <ESC>[0m (\"reset attributes\") command sequence is received from the",
+"  host.",
+" ",
+
+"SET TERMINAL CONTROLS { 7, 8 }",
+"  Determines whether VT220/320 or Wyse 370 function keys, arrow keys, etc,",
+"  that generate ANSI-format escape sequences should send 8-bit control",
+"  characters or 7-bit escape sequences.",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL CR-DISPLAY { CRLF, NORMAL }",
+"  Specifies how incoming carriage return characters are to be displayed",
+"  on your screen.",
+" ",
+
+#ifdef OS2
+#ifdef KUI
+"SET TERMINAL CURSOR { FULL, HALF, UNDERLINE } {ON, OFF, NOBLINK}",
+"  Selects the cursor style and visibility for the terminal screen.",
+#else
+"SET TERMINAL CURSOR { FULL, HALF, UNDERLINE } {ON, OFF}",
+"  Selects the cursor style and visibility for the terminal screen.",
+#endif /* KUI */
+" ",
+"SET TERMINAL DG-UNIX-MODE { ON, OFF }",
+"  Specifies whether the Data General emulations should accept control",
+"  sequences in Unix compatible format or in native DG format.  The",
+"  default is OFF, DG format.",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL DEBUG { ON, OFF }",
+"  Turns terminal session debugging on and off.  When ON, incoming control",
+"  characters are displayed symbolically, rather than be taken as formatting",
+"  commands.  SET TERMINAL DEBUG ON implies SET TELNET DEBUG ON.",
+" ",
+#ifdef OS2
+"SET TERMINAL DG-UNIX-MODE { ON, OFF }",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL ECHO { LOCAL, REMOTE }",
+"  Specifies which side does the echoing during terminal connection.",
+" ",
+
+"SET TERMINAL ESCAPE-CHARACTER { ENABLED, DISABLED }",
+"  Turns on/off the ability to escape back from CONNECT mode using the SET",
+#ifdef OS2
+"  ESCAPE character.  If you disable it you can still get back using Alt-key",
+"  combinations as shown in the status line.  Also see HELP SET ESCAPE.",
+#else
+"  ESCAPE character.  If you disable it, Kermit returns to its prompt only",
+"  when the connection is closed by the other end.  USE WITH EXTREME CAUTION.",
+"  Also see HELP SET ESCAPE.",
+#endif /* OS2 */
+" ",
+
+#ifdef OS2
+#ifdef KUI
+"SET TERMINAL FONT <facename> <height>",
+"  Specifies the font to be used in the Kermit 95 window.  The font is",
+"  determined by the choice of a facename and a height measured in Points.",
+"  The available facenames are those installed in the Font Control Panel.",
+" ",
+#else /* KUI */
+#ifdef OS2ONLY
+"SET TERMINAL FONT { CP437, CP850, CP852, CP862, CP866, DEFAULT }",
+"  CP437 - Original PC code page",
+"  CP850 - \"Multilingual\" (West Europe) code page",
+"  CP852 - East Europe Roman Alphabet code page (for Czech, Polish, etc)",
+"  CP862 - Hebrew code page",
+"  CP866 - Cyrillic (Russian, Belorussian, and Ukrainian) code page",
+" ",
+"  Loads a soft into the video adapter for use during terminal emulation.",
+"  Use this command when your OS/2 system does not have the desired code.",
+"  page.  Can be used only in full-screen sessions.  Also see SET TERMINAL",
+"  CODE-PAGE and SET TERMINAL REMOTE-CHARACTER-SET.",
+" ",
+#endif /* OS2ONLY */
+#endif /* KUI */
+
+#ifdef NT
+"SET TERMINAL HEIGHT <number>",
+"  Changes the number of rows (lines) to use during terminal emulation, not",
+"  counting the status line.  Recommended values are 24, 42, and 49 (or 25,",
+"  43, and 50 if SET TERMINAL STATUSLINE is OFF.)",
+#else
+"SET TERMINAL HEIGHT <number>"
+"  Changes the number of rows (lines) to use during terminal emulation, not",
+"  counting the status line.  Windowed sessions can use any value from 8 to",
+"  101.  Fullscreen sessions are limited to 24, 42, 49, or 59.  Not all"
+"  heights are supported by all video adapters.",
+#endif /* NT */
+#else  /* OS2 */
+"SET TERMINAL HEIGHT <number>",
+"  Tells C-Kermit how many rows (lines) are on your CONNECT-mode screen.",
+#endif /* OS2 */
+" ",
+
+#ifdef CKTIDLE
+"SET TERMINAL IDLE-TIMEOUT <number>",
+"  Sets the limit on idle time in CONNECT mode to the given number of",
+"  seconds.  0 (the default) means no limit.",
+" ",
+"SET TERMINAL IDLE-ACTION { EXIT, HANGUP, OUTPUT [ text ], RETURN }",
+"  Specifies the action to be taken when a CONNECT session is idle for the",
+"  number of seconds given by SET TERMINAL IDLE-TIMEOUT.  The default action",
+"  is to RETURN to command mode.  EXIT exits from Kermit; HANGUP hangs up the",
+"  connection, and OUTPUT sends the given text to the host without leaving",
+"  CONNECT mode; if no text is given a NUL (0) character is sent.",
+#ifdef TNCODE
+" ",
+"And for Telnet connections:",
+" ",
+"SET TERMINAL IDLE-ACTION { TELNET-NOP, TELNET-AYT }",
+"  Sends the indicated Telnet protocol message: No Operation (NOP) or",
+"  \"Are You There?\" (AYT).",
+#endif /* TNCODE */
+" ",
+#endif /* CKTIDLE */
+
+#ifdef OS2
+
+"SET TERMINAL KDB-FOLLOWS-GL/GR { ON, OFF }",
+" Specifies whether or not the keyboard character set should follow the",
+"  active GL and GR character sets.  This feature is OFF by default and",
+"  should not be used unless it is specificly required by the host",
+"  application.",
+" ",
+
+"SET TERMINAL KEY <mode> /LITERAL <keycode> <text>",
+"SET TERMINAL KEY <mode> DEFAULT",
+"SET TERMINAL KEY <mode> CLEAR",
+"  Configures the key whose <keycode> is given to send the given text when",
+"  pressed while <mode> is active.  <mode> may be any of the valid terminal",
+"  types or the special modes \"EMACS\", \"HEBREW\" or \"RUSSIAN\".  DEFAULT",
+"  restores all default key mappings for the specified mode.  CLEAR erases",
+"  all the key mappings.  If there is no text, the default key binding is",
+#ifndef NOCSETS
+"  restored for the key k.  SET TERMINAL KEY mappings take place before",
+"  terminal character-set translation.  SET KEY mappings take precedence over",
+"  SET TERMINAL KEY <terminal type> settings.",
+#else
+"  restored for the key.  SET KEY mappings take precedence over SET TERMINAL",
+"  KEY <terminal type> settings.",
+#endif /* NOCSETS */
+"  The /LITERAL switch may be used to instruct Kermit to ignore character-set",
+"  translations when sending this definition to the host.",
+" ",
+"  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.",
+" ",
+"  To find out the keycode and mapping for a particular key, use the SHOW",
+"  KEY command.  Use the SAVE KEYS command to save all settings to a file.",
+" ",
+"SET TERMINAL KEYBOARD-MODE { NORMAL, EMACS, RUSSIAN, HEBREW }",
+"  Select a special keyboard mode for use in the terminal screen.",
+" ",
+
+"SET TERMINAL KEYPAD-MODE { APPLICATION, NUMERIC }",
+"  Specifies the \"mode\" of the numeric keypad for VT terminal emulation.",
+"  Use this command in case the host or application wants the keypad to be",
+"  in a different mode than it's in, but did not send the escape sequence",
+"  to put it in the needed mode.",
+" ",
+#ifdef KUI
+"SET TERMINAL LINE-SPACING <float>",
+"  Specifies the line spacing used when displaying text.  The default is 1.0.",
+"  Valid values range from 1.0 to 3.0 inclusive.",
+" ",
+#endif /* KUI */
+#endif /* OS2 */
+
+#ifndef NOCSETS
+#ifdef OS2
+"SET TERMINAL LOCAL-CHARACTER-SET <local-cs>",
+"  Specifies the character set used by K-95 locally.  If you don't specify",
+#ifdef OS2ONLY
+"  the local character-set, the current TERMINAL FONT is used if you have",
+"  given a SET TERMINAL FONT command; otherwise the current codepage is used.",
+#else
+"  the local character-set, the current code page is used.",
+#endif /* OS2ONLY */
+" ",
+"  When the local and remote character sets differ, Kermit translates between",
+"  them during CONNECT.  By default, the remote character set is Latin1 and",
+"  the local one is your current code page.",
+#ifdef NT
+" ",
+"  In Windows NT, Unicode is used as the local character-set regardless of",
+"  this setting.",
+#endif /* NT */
+" ",
+"See also SET TERMINAL REMOTE-CHARACTER-SET",
+" ",
+#endif /* OS2 */
+#endif /* NOCSETS */
+
+#ifdef OS2
+"SET TERMINAL LOCKING-SHIFT { OFF, ON }",
+"  Tells whether to send Shift-In/Shift-Out (Ctrl-O and Ctrl-N) to switch",
+"  between 7-bit and 8-bit characters sent during terminal emulation over",
+"  7-bit connections.  OFF by default.",
+#else
+"SET TERMINAL LOCKING-SHIFT { OFF, ON }",
+"  Tells Kermit whether to use Shift-In/Shift-Out (Ctrl-O and Ctrl-N) to",
+"  switch between 7-bit and 8-bit characters during CONNECT.  OFF by default.",
+#endif /* OS2 */
+" ",
+
+#ifdef OS2
+"SET TERMINAL MARGIN-BELL { ON [column], OFF }",
+"  Determines whether the margin-bell is activated and what column it should",
+"  ring at.  OFF by default.",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL NEWLINE-MODE { OFF, ON }",
+"  Tells whether to send CRLF (Carriage Return and Line Feed) when you type",
+"  CR (press the Return or Enter key) in CONNECT mode.",
+" ",
+
+#ifdef OS2
+"SET TERMINAL OUTPUT-PACING <milliseconds>",
+"  Tells how long to pause between sending each character to the host during",
+"  CONNECT mode.  Normally not needed but sometimes required to work around",
+"  TRANSMISSION BLOCKED conditions when pasting into the terminal window.",
+" ",
+
+#ifdef PCTERM
+"SET TERMINAL PCTERM { ON, OFF }",
+"  Activates or deactivates the PCTERM terminal emulation keyboard mode.",
+"  When PCTERM is ON all keystrokes in the terminal screen are sent to the",
+"  host as make/break (down/up) codes instead of as characters from the",
+"  REMOTE-CHARACTER-SET, and all keyboard mappings, including Kverbs and the",
+"  escape character are disabled.  To turn off PCTERM keyboard mode while in",
+"  CONNECT mode press Control-CapsLock.  PCTERM is OFF by default.",
+" ",
+#endif /* PCTERM */
+#endif /* OS2 */
+
+#ifdef OS2
+"SET TERMINAL PRINT { AUTO, COPY, OFF, USER }",
+"  Allows selective control of various types of printing from the Terminal",
+"  session.  AUTO prints a line of text from the terminal screen whenever",
+"  the cursor is moved off the line.  COPY prints every byte received as",
+"  it is received without interpretation.  USER prints every byte after",
+"  interpretation by the terminal emulator translates character-sets and",
+"  construct escape sequences, ...  The default is OFF.",
+" ",
+#else
+#ifdef XPRINT
+"SET TERMINAL PRINT { ON, OFF }",
+"  Enables and disables host-initiated transparent printing in CONNECT mode.",
+" ",
+#endif /* XPRINT */
+#endif /* OS2 */
+
+#ifdef OS2
+#ifndef NOCSETS
+"SET TERMINAL REMOTE-CHARACTER-SET <remote-cs> [ { G0,G1,G2,G3 }... ]",
+"  Specifies the character set used by the remote host, <remote-cs>.",
+"  When the local and remote character sets differ, Kermit translates",
+"  between them during CONNECT.  By default, the remote character set is",
+"  Latin1 and the local one is your current code page.  Optionally, you can",
+"  also designate the character set to the G0..G3 graphic tables.",
+" ",
+#endif /* NOCSETS */
+#endif /* OS2 */
+
+#ifdef OS2
+"SET TERMINAL ROLL-MODE { INSERT, OVERWRITE, KEYSTROKES [ option ] }",
+"  Tells whether new data when received from the host is entered into the",
+"  scrollback buffer at the current rollback position (OVERWRITE) or at the",
+"  end of the buffer (INSERT).  The default is INSERT.  Typing is allowed",
+"  during rollbacks in either mode, according to SET TERM ROLL KEYSTROKES:",
+"  SEND (the default) means to process keystrokes normally; IGNORE means to",
+"  ignore them when the screen is scrolled back; RESTORE-AND-SEND is like",
+"  SEND but restores the screen to its active position first.",
+" ",
+
+"SET TERMINAL SCREEN-MODE { NORMAL, REVERSE }",
+"  When set to REVERSE the foreground and background colors are swapped as",
+"  well as the application of the foreground and background intensity bits.",
+"  The default is NORMAL.",
+" ",
+
+"SET TERMINAL SCREEN-OPTIMIZE { ON, OFF }",
+"  When set to ON, the default, Kermit only paints the screen with characters",
+"  that have changed since the last screen paint.  When OFF, the screen is",
+"  completely repainted each time there is a change.",
+" ",
+
+"SET TERMINAL SCREEN-UPDATE { FAST, SMOOTH } [ <milliseconds> ]",
+"  Chooses the mechanism used for screen updating and the update frequency.",
+"  Defaults are FAST scrolling with updates every 100 milliseconds.",
+" ",
+
+"SET TERMINAL SCROLLBACK <lines>",
+"  Sets size of CONNECT virtual screen buffer.  <lines> includes the active",
+"  terminal screen.  The minimum is 256.  The maximum is 2 million.  The",
+"  default is 2000.",
+" ",
+
+"SET TERMINAL SEND-DATA { ON, OFF }",
+"  Determines whether ASCII emulations such as WYSE 30,50,60 or TVI 910+,925,",
+"  950 may send their screen contents to the host upon request.  Allowing the",
+"  screen to be read by the host is a significant security risk.  The default",
+"  is OFF and should only be changed after a security evaluation of host",
+"  environment.",
+" ",
+
+"SET TERMINAL SEND-END-OF-BLOCK { CRLF_ETX, US_CR }",
+"  Determines which set of characters should be used as end of line and end",
+"  of transmission indicators when sending screen data to the host",
+" ",
+
+"SET TERMINAL SGR-COLORS { ON, OFF }",
+"  ON (default) means allow host control of colors; OFF means ignore host",
+"  escape sequences to set color.",
+" ",
+
+"SET TERMINAL SNI-CH.CODE { ON, OFF }",
+"  This command controls the state of the CH.CODE key.  It is the equivalent",
+"  to the SNI_CH_CODE Keyboard verb.  The SNI terminal uses CH.CODE to",
+"  easily switch between the National Language character set and U.S. ASCII.",
+"  The default is ON which means to display characters as U.S. ASCII.  When",
+"  OFF the lanuage specified by SET TERMINAL SNI-LANUAGE is used to display",
+"  characters when 7-bit character sets are in use."
+" ",
+"SET TERMINAL SNI-FIRMWARE-VERSIONS <kbd-version> <terminal-version>",
+"  Specifies the Firmware Version number that should be reported to the host",
+"  when the terminal is queried.  The default is 920031 for the keyboard",
+"  and 830851 for the terminal.",
+" ",
+"SET TERMINAL SNI-LANGUAGE <national-language>",
+"  An alias for SET TERMINAL VT-LANUAGE, this command specifies the national",
+"  language character-set that should be used when the NRC mode is activated",
+"  for VT emulations or when CH.CODE is OFF for SNI emulations.  The default",
+"  language for SET TERMINAL TYPE SNI-97801 is \"German\".",
+" ",
+"SET TERMINAL SNI-PAGEMODE { ON, OFF }",
+"  Determines whether or not page mode is active.  OFF by default.",
+" ",
+"SET TERMINAL SNI-SCROLLMODE { ON, OFF }",
+"  Determines whether or not scroll mode is active.  OFF by default.",
+" ",
+"SET TERMINAL STATUSLINE { ON, OFF }",
+"  ON (default) enables the Kermit status line in the terminal screen.",
+"  OFF removes it, making the line available for use by the host.",
+" ",
+
+"SET TERMINAL TRANSMIT-TIMEOUT <seconds>",
+"  Specifies the maximum amount of time K-95 waits before returning to the",
+"  prompt if your keystrokes can't be transmitted for some reason, such as a",
+"  flow-control deadlock.",
+" ",
+#endif /* OS2 */
+
+#ifdef CK_TRIGGER
+"SET TERMINAL TRIGGER <string>",
+"  Specifies a string that, when detected during any subsequent CONNECT",
+"  session, is to cause automatic return to command mode.  Give this command",
+"  without a string to cancel the current trigger.  See HELP CONNECT for",
+"  additional information.",
+" ",
+#endif /* CK_TRIGGER */
+
+#ifdef OS2
+"SET TERMINAL URL-HIGHLIGHT { ON <attribute>, OFF }",
+"  Specifies whether K-95 should highlight URLs and which screen attribute",
+"  should be used.  The screen attributes can be one of NORMAL, BLINK, BOLD,",
+"  DIM, INVISIBLE, REVERSE, or UNDERLINE.  The default is ON using the",
+"  BOLD screen attribute.",
+" ",
+"SET TERMINAL VIDEO-CHANGE { DISABLED, ENABLED }",
+"  Specifies whether K-95 should change video modes automatically in response",
+#ifdef NT
+"  to escape sequences from the other computer.  ENABLED by default (except",
+"  on Windows 95).",
+#else /* NT */
+"  to escape sequences from the other computer.  ENABLED by default.",
+#endif /* NT */
+" ",
+
+"SET TERMINAL VT-LANGUAGE <language>",
+"  Specifies the National Replacement Character Set (NRC) to be used when",
+"  NRC mode is activated.  The default is \"North American\".",
+" ",
+"SET TERMINAL VT-NRC-MODE { ON, OFF }",
+"  OFF (default) chooses VT multinational Character Set mode.  OFF chooses",
+"  VT National Replacement Character-set mode.  The NRC is selected with",
+"  SET TERMINAL VT-LANGUAGE",
+" ",
+
+#ifdef NT
+"SET TERMINAL WIDTH <cols>",
+"  Tells the number of columns in the terminal screen.",
+" ",
+"  The default is 80.  You can also use 132.  Other widths can be chosen but",
+"  are usually not supported by host software.",
+" ",
+#else
+"SET TERMINAL WIDTH <cols>",
+"  Tells how many columns define the terminal size.",
+" ",
+"Default is 80.  In Windowed OS/2 2.x sessions, this value may not be changed",
+"In Windowed OS/2 WARP 3.x sessions, this value may range from 20 to 255.",
+"In Full screen sessions, values of 40, 80, and 132 are valid.  Not all",
+"combinations of height and width are supported on all adapters.",
+" ",
+#endif /* NT */
+"SET TERMINAL WRAP { OFF, ON }",
+"  Tells whether the terminal emulator should automatically wrap long lines",
+"  on your screen.",
+" ",
+#else
+
+"SET TERMINAL WIDTH <number>",
+" \
+Tells Kermit how many columns (characters) are on your CONNECT-mode screen.",
+" ",
+#endif /* OS2 */
+"Type SHOW TERMINAL to see current terminal settings.",
+"" };
+#endif /* NOLOCAL */
+
+#ifdef NETCONN
+static char *hxyhost[] = {
+"SET HOST [ switches ] hostname-or-address [ service ] [ protocol-switch ]",
+"  Establishes a connection to the specified network host on the currently",
+"  selected network type.  For TCP/IP connections, the default service is",
+"  TELNET; specify a different TCP port number or service name to choose a",
+"  different service.  The first set of switches can be:",
+" ",
+" /NETWORK-TYPE:name",
+"   Makes the connection on the given type of network.  Equivalent to SET",
+"   NETWORK TYPE name prior to SET HOST, except that the selected network",
+"   type is used only for this connection.  Type \"set host /net:?\" to see",
+#ifdef NETCMD
+"   a list.  /NETWORK-TYPE:COMMAND means to make the connection through the",
+"   given system command, such as \"rlogin\" or \"cu\".",
+#else
+"   a list.",
+#endif /* NETCMD */
+" ",
+" /CONNECT",
+"   \
+Enter CONNECT (terminal) mode automatically if the connection is successful.",
+" ",
+" /SERVER",
+"   Enter server mode automatically if the connection is successful.",
+" ",
+" /USERID:[<name>]",
+"   This switch is equivalent to SET LOGIN USERID <name> or SET TELNET",
+"   ENVIRONMENT USER <name>.  If a string is given, it sent to host during",
+"   Telnet negotiations; if this switch is given but the string is omitted,",
+"   no user ID is sent to the host.  If this switch is not given, your",
+"   current USERID value, \\v(userid), is sent.  When a userid is sent to the",
+"   host it is a request to login as the specified user.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /PASSWORD:[<string>]",
+"   This switch is equivalent to SET LOGIN PASSWORD.  If a string is given,",
+"   it is treated as the password to be used (if required) by any Telnet",
+"   Authentication protocol (Kerberos Ticket retrieval, Secure Remote",
+"   Password, or X.509 certificate private key decryption.)  If no password",
+"   switch is specified a prompt is issued to request the password if one",
+"   is required for the negotiated authentication method.",
+" ",
+#endif /* CK_AUTHENTICATION */
+"The protocol-switches can be:",
+" ",
+" /NO-TELNET-INIT",
+"   Do not send initial Telnet negotiations even if this is a Telnet port.",
+" ",
+" /RAW-SOCKET",
+"   This is a connection to a raw TCP socket.",
+" ",
+#ifdef RLOGCODE
+" /RLOGIN",
+"   Use Rlogin protocol even if this is not an Rlogin port.",
+" ",
+#endif /* RLOGCODE */
+" /TELNET",
+"   Send initial Telnet negotiations even if this is not a Telnet port.",
+" ",
+#ifdef CK_KERBEROS
+#ifdef RLOGCODE
+#ifdef KRB4
+" /K4LOGIN",
+"   Use Kerberos IV klogin protocol even if this is not a klogin port.",
+" ",
+#ifdef CK_ENCRYPTION
+" /EK4LOGIN",
+"   Use Kerberos IV Encrypted login protocol even if this is not an eklogin",
+"   port.",
+" ",
+#endif /* CK_ENCRYPTION */
+#endif /* KRB4 */
+#ifdef KRB5
+" /K5LOGIN",
+"   Use Kerberos V klogin protocol even if this is not a klogin port.",
+" ",
+#ifdef CK_ENCRYPTION
+" /EK5LOGIN",
+"   Use Kerberos V Encrypted login protocol even if this is not an eklogin",
+"   port.",
+" ",
+#endif /* CK_ENCRYPTION */
+#endif /* KRB5 */
+#endif /* RLOGCODE */
+#endif /* CK_KERBEROS */
+#ifdef CK_SSL
+" /SSL",
+"   Perform SSL negotiations.",
+" ",
+" /SSL-TELNET",
+"   Perform SSL negotiations and if successful start Telnet negotiations.",
+" ",
+" /TLS",
+"   Perform TLS negotiations.",
+" ",
+" /TLS-TELNET",
+"   Perform TLS negotiations and if successful start Telnet negotiations.",
+" ",
+#endif /* CK_SSL */
+"Examples:",
+"  SET HOST kermit.columbia.edu",
+"  SET HOST /CONNECT kermit.columbia.edu",
+"  SET HOST * 1649",
+"  SET HOST /SERVER * 1649",
+"  SET HOST 128.59.39.2",
+"  SET HOST madlab.sprl.umich.edu 3000",
+"  SET HOST xyzcorp.com 2000 /RAW-SOCKET",
+#ifdef SSHBUILTIN
+"  SET HOST /NET:SSH kermit.columbia.edu /x11-forwarding:on", 
+#endif /* SSHBUILTIN */
+#ifdef NETCMD
+"  SET HOST /CONNECT /COMMAND rlogin xyzcorp.com",
+#endif /* NETCMD */
+" ",
+#ifdef SUPERLAT
+"Notes:",
+" ",
+" . The TELNET command is equivalent to SET NETWORK TYPE TCP/IP,",
+"   SET HOST name [ port ] /TELNET, IF SUCCESS CONNECT",
+" ",
+" . For SUPERLAT connections, the hostname-or-address may be either a service",
+"   name, or a node/port combination, as required by your LAT host.",
+#else
+"The TELNET command is equivalent to SET NETWORK TYPE TCP/IP,",
+"SET HOST name [ port ] /TELNET, IF SUCCESS CONNECT",
+#endif /* SUPERLAT */
+" ",
+"Also see SET NETWORK, TELNET, SET TELNET.",
+"" };
+
+static char *hmxyauth[] = {
+"Synatx: SET AUTHENTICATION <auth_type> <parameter> <value>",
+"  Sets defaults for the AUTHENTICATE command:",
+" ",
+#ifdef CK_KERBEROS
+"SET AUTHENTICATION KERBEROS5 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.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } AUTODESTROY",
+"  { ON-CLOSE, ON-EXIT, NEVER }",
+"  When ON, Kermit will destroy all credentials in the default",
+"  credentials cache upon Kermit termination.  Default is NEVER.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } AUTOGET { ON, OFF }",
+"  When ON, if the host offers Kerberos 4 or Kerberos 5 authentication",
+"  and Kermit is configured to use that authentication method and there",
+"  is no TGT, Kermit will automatically attempt to retrieve one by",
+"  prompting for the password (and principal if needed.)  Default is ON.",
+" ",
+"SET AUTHENTICATION KERBEROS5 CREDENTIALS-CACHE <filename>",
+"  Allows an alternative credentials cache to be specified.  This is useful",
+"  when you need to maintain two or more sets of credentials for different",
+"  realms or roles.  The default is specified by the environment variable",
+"  KRB5CCNAME or as reported by the Kerberos 5 library.",
+" ",
+"SET AUTHENTICATION KERBEROS5 FORWARDABLE { ON, OFF }",
+"  When ON, specifies that Kerberos 5 credentials should be forwardable to",
+"  the host.  If SET TELNET AUTHENTICATION FORWARDING is ON, forwardable",
+"  credentials are sent to the host.  The default is OFF.",
+" ",
+"SET AUTHENTICATION KERBEROS5 GET-K4-TGT { ON, OFF }",
+"  When ON, specifies that Kerberos 4 credentials should be requested each",
+"  time Kerberos 5 credentials are requested with AUTH KERBEROS5 INIT.",
+"  Default is OFF.",
+" ",
+"SET AUTHENTICATION KERBEROS4 INSTANCE <instance>",
+"  Allows a Kerberos 4 instance to be specified as a default (if needed).",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } KEYTAB <filename>",
+"  Specifies the location of the keytab file used to authenticate incoming",
+"  connections.  The default is none, which means to use the default value",
+"  configured in the Kerberos installation.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } LIFETIME <minutes>",
+"  Specifies the lifetime of the TGTs requested from the KDC.  The default",
+"  is 600 minutes (10 hours).",
+" ",
+"SET AUTHENTICATION KERBEROS5 NO-ADDRESSES { ON, OFF }",
+"  Specifies whether or not IP addresses will be inserted into the TGT."
+"  Default is OFF.",
+" ",
+"SET AUTHENTICATION KERBEROS4 PREAUTH { ON, OFF }",
+"  Allows Kerberos 4 preauthenticated TGT requests to be turned off.  The",
+"  default is ON.  Only use if absolutely necessary.  We recommend that",
+"  preauthenticated requests be required for all tickets returned by a KDC",
+"  to a requestor.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } PRINCIPAL <name>",
+"  When Kermit starts, it attempts to set the principal name to that stored",
+"  in the current credentials cache.  If no credential cache exists, the",
+"  current SET LOGIN USERID value is used.  SET LOGIN USERID is set to the",
+"  operating system's current username when Kermit is started.  To force",
+"  Kermit to prompt the user for the principal name when requesting TGTs,",
+"  place:",
+" ",
+"    SET AUTH K4 PRINCIPAL {}",
+"    SET AUTH K5 PRINCIPAL {}",
+" ",
+"  in the Kermit initialization file or connection script.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } PROMPT PASSWORD <prompt>",
+"  Specifies a custom prompt to be used when prompting for a password.",
+"  The Kerberos prompt strings may contain two %s replacement fields.",
+"  The first %s is replaced by the principal name; the second by the realm.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } PROMPT PRINCIPAL <prompt>",
+"  Specifies a custom prompt to be used when prompting for the Kerberos",
+"  principal name.  No %s replacement fields may be used.  Kermit prompts",
+"  for a principal name when retrieving a TGT if the command:",
+" ",
+"    SET AUTHENTICATION { KERBEROS4, KERBEROS5 } PRINCIPAL {}",
+" ",
+"  has been issued.",
+" ",
+"SET AUTHENTICATION KERBEROS5 PROXIABLE { ON, OFF }",
+"  When ON, specifies that Kerberos 5 credentials should be proxiable.",
+"  Default is OFF.",
+" ",
+"SET AUTHENTICATION KERBEROS5 RENEWABLE <minutes>",
+"  When <minutes> is greater than the ticket lifetime a TGT may be renewed",
+"  with AUTH K5 INIT /RENEW instead of getting a new ticket as long as the",
+"  ticket is not expired and its within the renewable lifetime.  Default is",
+"  0 (zero) minutes.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } REALM <name>",
+"  If no default is set, the default realm configured for the Kerberos",
+"  libraries is used.  Abbreviations accepted.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } SERVICE-NAME <name>",
+"  This command specifies the service ticket name used to authenticate",
+"  to the host when Kermit is used as a client; or the service ticket",
+"  name accepted by Kermit when it is acting as the host.",
+"  If no default is set, the default service name for Kerberos 4 is",
+"  \"rcmd\" and for Kerberos 5 is \"host\".",
+" ",
+#endif /* CK_KERBEROS */
+#ifdef CK_SRP
+"SET AUTHENTICATION SRP PROMPT PASSWORD <prompt>",
+"  Specifies a custom prompt to be used when prompting for a password.",
+"  The SRP prompt string may contain one %s replacement fields which is",
+"  replaced by the login userid.",
+" ",
+#endif /* CK_SRP */
+#ifdef CK_SSL
+"In all of the following commands \"SSL\" and \"TLS\" are aliases.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } CIPHER-LIST <list of ciphers>",
+"Applies to both SSL and TLS.  A colon separated list of any of the following",
+"(case sensitive) options depending on the options chosen when OpenSSL was ",
+"compiled: ",
+" ",
+"  Key Exchange Algorithms:",
+"    \"kRSA\"      RSA key exchange",
+"    \"kDHr\"      Diffie-Hellman key exchange (key from RSA cert)",
+"    \"kDHd\"      Diffie-Hellman key exchange (key from DSA cert)",
+"    \"kEDH\"      Ephemeral Diffie-Hellman key exchange (temporary key)",
+"    \"kKRB5\"     Kerberos 5",
+" ",
+"  Authentication Algorithm:",
+"    \"aNULL\"     No authentication",
+"    \"aRSA\"      RSA authentication",
+"    \"aDSS\"      DSS authentication",
+"    \"aDH\"       Diffie-Hellman authentication",
+"    \"aKRB5\"     Kerberos 5",
+" ",
+"  Cipher Encoding Algorithm:",
+"    \"eNULL\"     No encodiing",
+"    \"DES\"       DES encoding",
+"    \"3DES\"      Triple DES encoding",
+"    \"RC4\"       RC4 encoding",
+"    \"RC2\"       RC2 encoding",
+"    \"IDEA\"      IDEA encoding",
+" ",
+"  MAC Digest Algorithm:",
+"    \"MD5\"       MD5 hash function",
+"    \"SHA1\"      SHA1 hash function",
+"    \"SHA\"       SHA hash function (should not be used)",
+" ",
+"  Aliases:",
+"    \"SSLv2\"     all SSL version 2.0 ciphers (should not be used)",
+"    \"SSLv3\"     all SSL version 3.0 ciphers",
+"    \"EXP\"       all export ciphers (40-bit)",
+"    \"EXPORT56\"  all export ciphers (56-bit)",
+"    \"LOW\"       all low strength ciphers (no export)",
+"    \"MEDIUM\"    all ciphers with 128-bit encryption",
+"    \"HIGH\"      all ciphers using greater than 128-bit encryption",
+"    \"RSA\"       all ciphers using RSA key exchange",
+"    \"DH\"        all ciphers using Diffie-Hellman key exchange",
+"    \"EDH\"       all ciphers using Ephemeral Diffie-Hellman key exchange",
+"    \"ADH\"       all ciphers using Anonymous Diffie-Hellman key exchange",
+"    \"DSS\"       all ciphers using DSS authentication",
+"    \"KRB5\"      all ciphers using Kerberos 5 authentication",
+"    \"NULL\"      all ciphers using no encryption",
+" ",
+"Each item in the list may include a prefix modifier:",
+" ",
+"    \"+\"         move cipher(s) to the current location in the list",
+"    \"-\"         remove cipher(s) from the list (may be added again by",
+"                a subsequent list entry)",
+"    \"!\"         kill cipher from the list (it may not be added again",
+"                by a subsequent list entry)",
+" ",
+"If no modifier is specified the entry is added to the list at the current ",
+"position.  \"+\" may also be used to combine tags to specify entries such as "
+,
+"\"RSA+RC4\" describes all ciphers that use both RSA and RC4.",
+" ",
+"For example, all available ciphers not including ADH key exchange:",
+" ",
+"  ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP",
+" ",
+"All algorithms including ADH and export but excluding patented algorithms: ",
+" ",
+"  HIGH:MEDIUM:LOW:EXPORT56:EXP:ADH:!kRSA:!aRSA:!RC4:!RC2:!IDEA",
+" ",
+"The OpenSSL command ",
+" ",
+"  openssl.exe ciphers -v <list of ciphers> ",
+" ",
+"may be used to list all of the ciphers and the order described by a specific",
+"<list of ciphers>.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } CRL-DIR <directory>",
+"specifies a directory that contains certificate revocation files where each",
+"file is named by the hash of the certificate that has been revoked.",
+" ",
+"  OpenSSL expects the hash symlinks to be made like this:",
+" ",
+"    ln -s crl.pem `openssl crl -hash -noout -in crl.pem`.r0",
+" ",
+"  Since not all file systems have symlinks you can use the following command",
+"  in Kermit to copy the crl.pem file to the hash file name.",
+" ",
+"     copy crl.pem {\\fcommand(openssl.exe crl -hash -noout -in crl.pem).r0}",
+" ",
+"  This produces a hash based on the issuer field in the CRL such ",
+"  that the issuer field of a Cert may be quickly mapped to the ",
+"  correct CRL.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } CRL-FILE <filename>",
+"specifies a file that contains a list of certificate revocations.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DEBUG { ON, OFF }",
+"specifies whether debug information should be displayed about the SSL/TLS",
+"connection.  When DEBUG is ON, the VERIFY command does not terminate",
+"connections when set to FAIL-IF-NO-PEER-CERT when a certificate is",
+"presented that cannot be successfully verified.  Instead each error",
+"is displayed but the connection automatically continues.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DH-PARAM-FILE <filename>",
+"  Specifies a file containing DH parameters which are used to generate",
+"  temporary DH keys.  If a DH parameter file is not provided Kermit uses a",
+"  fixed set of parameters depending on the negotiated key length.  Kermit",
+"  provides DH parameters for key lengths of 512, 768, 1024, 1536, and 2048",
+"  bits.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DSA-CERT-CHAIN-FILE <filename>",
+"  Specifies a file containing a DSA certificate chain to be sent along with",
+"  the DSA-CERT to the peer.  This file must only be specified if Kermit is",
+"  being used as a server and the DSA certificate was signed by an",
+"  intermediary certificate authority.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DSA-CERT-FILE <filename>",
+"  Specifies a file containing a DSA certificate to be sent to the peer to ",
+"  authenticate the host or end user.  The file may contain the matching DH ",
+"  private key instead of using the DSA-KEY-FILE command.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DSA-KEY-FILE <filename>",
+"Specifies a file containing the private DH key that matches the DSA ",
+"certificate specified with DSA-CERT-FILE.  This command is only necessary if",
+"the private key is not appended to the certificate in the file specified by",
+"DSA-CERT-FILE.",
+" ",
+"  Note: When executing a script in the background or when it is",
+"  running as an Internet Kermit Service Daemon, Kermit cannot support ",
+"  encrypted private keys.  When attempting to load a private key that is",
+"  encrypted, a prompt will be generated requesting the passphrase necessary",
+"  to decrypt the keyfile.  To automate access to the private key you must",
+"  decrypt the encrypted keyfile and create an unencrypted keyfile for use",
+"  by Kermit.  This can be accomplished by using the following command and",
+"  the passphrase:",
+" ",
+"  openssl dsa -in <encrypted-key-file> -out <unencrypted-key-file>",
+" ",
+"SET AUTHENTICATION { SSL, TLS } RANDOM-FILE <filename>",
+"  Specifies a file containing random data to be used as seed for the",
+"  Pseudo Random Number Generator.  The contents of the file are",
+"  overwritten with new random data on each use.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } RSA-CERT-CHAIN-FILE <filename>",
+"  Specifies a file containing a RSA certificate chain to be sent along with",
+"  the RSA-CERT to the peer.  This file must only be specified if Kermit is",
+"  being used as a server and the RSA certificate was signed by an",
+"  intermediary certificate authority.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } RSA-CERT-FILE <filename>",
+"  Specifies a file containing a RSA certificate to be sent to the peer to ",
+"  authenticate the host or end user.  The file may contain the matching RSA ",
+"  private key instead of using the RSA-KEY-FILE command.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } RSA-KEY-FILE <filename>",
+"  Specifies a file containing the private RSA key that matches the RSA",
+"  certificate specified with RSA-CERT-FILE.  This command is only necessary",
+"  if the private key is not appended to the certificate in the file specified"
+,
+"  by RSA-CERT-FILE.  ",
+" ",
+"  Note: When executing a script in the background or when it is",
+"  running as an Internet Kermit Service Daemon, Kermit cannot support ",
+"  encrypted private keys.  When attempting to load a private key that is",
+"  encrypted, a prompt will be generated requesting the passphrase necessary",
+"  to decrypt the keyfile.  To automate access to the private key you must",
+"  decrypt the encrypted keyfile and create an unencrypted keyfile for use",
+"  by Kermit.  This can be accomplished by using the following command and",
+"  the passphrase:",
+" ",
+"  openssl rsa -in <encrypted-key-file> -out <unencrypted-key-file>",
+" ",
+"SET AUTHENTICATION { SSL, TLS } VERBOSE { ON, OFF }",
+"  Specifies whether information about the authentication (ie, the",
+"  certificate chain) should be displayed upon making a connection.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } VERIFY { NO,PEER-CERT,FAIL-IF-NO-PEER-CERT }",
+"  Specifies whether certificates should be requested from the peer verified;",
+"  whether they should be verified when they are presented; and whether they",
+"  should be required.  When set to NO (the default for IKSD), Kermit does",
+"  not request that the peer send a certificate; if one is presented it is",
+"  ignored.  When set to PEER-CERT (the default when not IKSD), Kermit",
+"  requests a certificate be sent by the peer.  If presented, the certificate",
+"  is verified.  Any errors during the verification process result in",
+"  queries to the end user.  When set to FAIL-IF-NO-PEER-CERT, Kermit",
+"  requests a certificate be sent by the peer.  If the certificate is not",
+"  presented or fails to verify, the connection is terminated without",
+"  querying the user.",
+" ",
+"  If an anonymous cipher (i.e., ADH) is desired, the NO setting must be",
+"  used.  Otherwise, the receipt of the peer certificate request is",
+"  interpreted as a protocol error and the negotiation fails.",
+" ",
+"  If you wish to allow the peer to authenticate using either an X509",
+"  certificate to userid mapping function or via use of a ~/.tlslogin file",
+"  you must use either PEER-CERT or FAIL-IF-NO-PEER-CERT.  Otherwise, any",
+"  certificates that are presented is ignored.  In other words, use NO if you",
+"  want to disable the ability to use certificates to authenticate a peer.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } VERIFY-DIR <directory>",
+"  Specifies a directory that contains root CA certificate files used to",
+"  verify the certificate chains presented by the peer.  Each file is named",
+"  by a hash of the certificate.",
+" ",
+"  OpenSSL expects the hash symlinks to be made like this:",
+" ",
+"    ln -s cert.pem `openssl x509 -hash -noout -in cert.pem`.0",
+" ",
+"  Since not all file systems have symlinks you can use the following command",
+"  in Kermit to copy the cert.pem file to the hash file name.",
+" ",
+"    copy cert.pem {\\fcommand(openssl.exe x509 -hash -noout -in cert.pem).0}",
+" ",
+"  This produces a hash based on the subject field in the cert such that the",
+"  certificate may be quickly found.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } VERIFY-FILE <file>",
+"  Specifies a file that contains root CA certificates to be used for",
+"  verifying certificate chains.",
+" ",
+#endif /* CK_SSL */
+""
+};
+
+static char *hxynet[] = {
+"Syntax: SET NETWORK { TYPE network-type, DIRECTORY [ file(s)... ] }",
+" ",
+"Select the type of network to be used with SET HOST connections:",
+" ",
+#ifdef NETCMD
+"  SET NETWORK TYPE COMMAND   ; Make a connection through an external command",
+#endif /* NETCMD */
+#ifdef TCPSOCKET
+"  SET NETWORK TYPE TCP/IP    ; Internet: Telnet, Rlogin, etc.",
+#endif /* TCPSOCKET */
+#ifdef ANYX25
+"  SET NETWORK TYPE X.25      ; X.25 peer-to-peer connections.",
+#endif /* ANYX25 */
+#ifdef DECNET
+"  SET NETWORK TYPE PATHWORKS { LAT, CTERM } ; DEC LAT or CTERM connections.",
+#endif /* DECNET */
+#ifdef NPIPE
+"  SET NETWORK TYPE NAMED-PIPE <pipename>  ; OS/2 Named Pipe connections.",
+#endif /* NPIPE */
+#ifdef CK_NETBIOS
+"  SET NETWORK TYPE NETBIOS                ; NETBIOS peer-to-peer connections",
+#endif /* CK_NETBIOS */
+#ifdef SUPERLAT
+"  SET NETWORK TYPE SUPERLAT ; LAT connections (Meridian Technology SuperLAT)",
+#endif /* SUPERLAT */
+" ",
+"If only one network type is listed above, that is the default network for",
+#ifdef RLOGCODE
+"SET HOST commands.  Also see SET HOST, TELNET, RLOGIN.",
+#else
+#ifdef TNCODE
+"SET HOST commands.  Also see SET HOST, TELNET.",
+#else
+"SET HOST commands.  Also see SET HOST.",
+#endif /* TNCODE */
+#endif /* RLOGCODE */
+" ",
+"SET NETWORK DIRECTORY [ file [ file [ ... ] ] ]",
+"  Specifies the name(s) of zero or more network directory files, similar to",
+"  dialing directories (HELP DIAL for details).  The general format of a",
+"  network directory entry is:",
+" ",
+"    name network-type address [ network-specific-info ] [ ; comment ]",
+" ",
+"  For TCP/IP, the format is:",
+" ",
+"    name tcp/ip ip-hostname-or-address [ socket ] [ ; comment ]",
+" ",
+"You can have multiple network directories and you can have multiple entries",
+"with the same name.  SET HOST <name> and TELNET <name> commands look up the",
+"given <name> in the directory and, if found, fill in the additional items",
+"from the entry, and then try all matching entries until one succeeds.",
+""};
+
+#ifndef NOTCPOPTS
+static char *hxytcp[] = {
+#ifdef SOL_SOCKET
+"SET TCP ADDRESS <ip-address>",
+"  This allows a specific IP Address on a multihomed host to be used",
+"  instead of allowing the TCP/IP stack to choose.  This may be necessary",
+"  when using authentication or listening for an incoming connection.",
+"  Specify no <ip-address> to remove the preference.",
+" ",
+"SET TCP KEEPALIVE { ON, OFF }",
+"  Setting this ON might help to detect broken connections more quickly.",
+"  (default is ON.)",
+" ",
+"SET TCP LINGER { ON [timeout], OFF }",
+"  Setting this ON ensures that a connection doesn't close before all",
+"  outstanding data has been transferred and acknowledged.  The timeout is",
+"  measured in 10ths of milliseconds.  The default is ON with a timeout of 0.",
+" ",
+"SET TCP NODELAY { ON, OFF }",
+"  ON means send short TCP packets immediately rather than waiting",
+"  to accumulate a bunch of them before transmitting (Nagle Algorithm).",
+"  (default is OFF.)",
+" ",
+"SET TCP RECVBUF <number>",
+"SET TCP SENDBUF <number>",
+"   TCP receive and send buffer sizes.  (default is -1, use system defaults.)",
+" ",
+"These items let you tune TCP networking performance on a per-connection",
+"basis by adjusting parameters you normally would not have access to.  You",
+"should use these commands only if you feel that the TCP/IP protocol stack",
+"that Kermit is using is giving you inadequate performance, and then only if",
+"you understand the concepts (see, for example, the Comer TCP/IP books), and",
+"then at your own risk.  These settings are displayed by SHOW NETWORK.  Not",
+"all options are necessarily available in all Kermit versions; it depends on",
+"the underlying TCP/IP services.",
+" ",
+"The following TCP and/or IP parameter(s) may also be changed:",
+" ",
+#endif /* SOL_SOCKET */
+"SET TCP REVERSE-DNS-LOOKUP { AUTO, ON, OFF }",
+"  Tells Kermit whether to perform reverse DNS lookup on TCP/IP connections",
+"  so Kermit can determine the actual hostname of the host it is connected",
+"  to, which is useful for connections to host pools, and is required for",
+"  Kerberos connections to host pools and for incoming connections.  If the",
+"  other host does not have a DNS entry, the reverse lookup could take a long",
+"  time (minutes) to fail, but the connection will still be made.  Turn this",
+"  option OFF for speedier connections if you do not need to know exactly",
+"  which host you are connected to and you are not using Kerberos.  AUTO, the",
+"  default, means the lookup is done on hostnames, but not on numeric IP",
+"  addresses unless Kerberos support is installed.",
+#ifdef CK_DNS_SRV
+" ",
+"SET TCP DNS-SERVICE-RECORDS {ON, OFF}",
+"  Tells Kermit whether to try to use DNS SRV records to determine the",
+"  host and port number upon which to find an advertised service.  For",
+"  example, if a host wants regular Telnet connections redirected to some",
+"  port other than 23, this feature allows Kermit to ask the host which",
+"  port it should use.  Since not all domain servers are set up to answer",
+"  such requests, this feature is OFF by default.",
+#endif /* CK_DNS_SRV */
+#ifdef NT
+#ifdef CK_SOCKS
+" ",
+"SET TCP SOCKS-SERVER [<hostname or ip-address>]",
+"  If a hostname or ip-address is specified, Kermit will use the SOCKS",
+"  server when attempting outgoing connections.  If no hostname or",
+"  ip-address is specified, any previously specified SOCKS server will",
+"  be removed.",
+#endif /* CK_SOCKS */
+#endif /* NT */
+#ifndef NOHTTP
+" ",
+"SET TCP HTTP-PROXY [<hostname or ip-address>[:<port>]]",
+"  If a hostname or ip-address is specified, Kermit will use the Proxy",
+"  server when attempting outgoing connections.  If no hostname or",
+"  ip-address is specified, any previously specified Proxy server will",
+"  be removed.  If no port number is specified, the \"http\" service",
+"  will be used.",
+#endif /* NOHTTP */
+""};
+#endif /* NOTCPOPTS */
+#endif /* NETCONN */
+
+#ifdef TNCODE
+static char *hxytopt[] = {
+"SET TELOPT [ { /CLIENT, /SERVER } ] <option> -",
+"    { ACCEPTED, REFUSED, REQUESTED, REQUIRED } -",
+"    [ { ACCEPTED, REFUSED, REQUESTED, REQUIRED } ]",
+"  SET TELOPT lets you specify policy requirements for Kermit's handling of",
+"  Telnet option negotiations.  Setting an option REQUIRED causes Kermit",
+"  to offer the option to the peer and disconnect if the option is refused.",
+"  REQUESTED causes Kermit to offer an option to the peer.  ACCEPTED results",
+"  in no offer but Kermit will attempt to negotiate the option if it is",
+"  requested.  REFUSED instructs Kermit to refuse the option if it is",
+"  requested by the peer.",
+" ",
+"  Some options are negotiated in two directions and accept separate policies",
+"  for each direction; the first keyword applies to Kermit itself, the second",
+"  applies to Kermit's Telnet partner; if the second keyword is omitted, an",
+"  appropriate (option-specific) default is applied.  You can also include a",
+"  /CLIENT or /SERVER switch to indicate whether the given policies apply",
+"  when Kermit is the Telnet client or the Telnet server; if no switch is",
+"  given, the command applies to the client.",
+" ",
+"  Note that some of Kermit's Telnet partners fail to refuse options that",
+"  they do not recognize and instead do not respond at all.  In this case it",
+"  is possible to use SET TELOPT to instruct Kermit to REFUSE the option",
+"  before connecting to the problem host, thus skipping the problematic",
+"  negotiation.",
+" ",
+"  Use SHOW TELOPT to view current Telnet Option negotiation settings.",
+"  SHOW TELNET displays current Telnet settings.",
+""};
+
+static char *hxytel[] = {
+"Syntax: SET TELNET parameter value",
+" ",
+"For TCP/IP TELNET connections, which are in NVT (ASCII) mode by default:",
+" ",
+#ifdef CK_AUTHENTICATION
+#ifdef COMMENT
+"SET TELNET AUTHENICATION { ACCEPTED, REFUSED, REQUESTED, REQUIRED }",
+"  ACCEPT or REFUSE authentication bids, or actively REQUEST authentication.",
+"  REQUIRED refuses the connection if authentication is not successfully",
+"  negotiated.  ACCEPTED by default.",
+" ",
+#endif /* COMMENT */
+"SET TELNET AUTHENTICATION TYPE { AUTOMATIC, KERBEROS_IV, KERBEROS_V, ...",
+#ifdef NT
+"  ..., NTLM, SSL, SRP, NONE } [...]",
+#else /* NT */
+"  ..., SSL, SRP, NONE } [...]",
+#endif /* NT */
+"  AUTOMATIC is the default.  Available options can vary depending on the",
+"  features Kermit was built to support and the operating system",
+"  configuration; type SET TELNET AUTHENTICATION TYPE ? for a list.",
+" ",
+"  When Kermit is the Telnet client:",
+"    AUTOMATIC allows the host to choose the preferred type of authentication."
+,
+"    NONE instructs Kermit to refuse all authentication methods when the",
+"    authentication option is negotiated.  A list of one or more other values",
+"    allow a specific subset of the supported authentication methods to be",
+"    used.",
+" ",
+"  When Kermit is the Telnet server:",
+"    AUTOMATIC results in available authentication methods being offered",
+"    to the telnet client in the following order:",
+" ",
+#ifdef NT
+"      KERBEROS_V, KERBEROS_IV, SRP, SSL, NTLM",
+#else /* NT */
+"      KERBEROS_V, KERBEROS_IV, SRP, SSL, NTLM",
+#endif /* NT */
+" ",
+"  NONE results in no authentication methods being offered to the Telnet",
+"  server when the authentication option is negotiated.  The preferred",
+"  method of disabling authentication is:",
+" ",
+"    SET TELOPT /SERVER AUTHENTICATION REFUSE",
+" ",
+"  A list of one or more authentication methods specifies the order those",
+"  methods are to be offered to the telnet client.",
+#ifdef NT
+" ",
+"  If you wish to allow NTLM authentication to be used with the Microsoft",
+"  Windows 2000 or Services for Unix Telnet client you must specify a list",
+"  with NTLM as the first item in the list.  By default, NTLM is the last",
+"  item in the list because it does not provide any form of data encryption.",
+#endif /* NT */
+" ",
+#ifdef CK_KERBEROS
+"SET TELNET AUTHENTICATION FORWARDING { ON, OFF }",
+"  Set this to ON to forward Kerberos V ticket-granting-tickets to the host",
+"  after authentication is complete.  OFF by default.",
+" ",
+#endif /* CK_KERBEROS */
+"SET TELNET AUTHENTICATION ENCRYPT-FLAG { ANY, NONE, TELOPT }",
+"  Use this command to specify which AUTH telopt encryption flags may be",
+"  accepted in client mode or offered in server mode.  The default is ANY.",
+" ",
+"SET TELNET AUTHENTICATION HOW-FLAG { ANY, ONE-WAY, MUTUAL }",
+"  Use this command to specify which AUTH telopt how flags may be",
+"  accepted in client mode or offered in server mode.  The default is ANY.",
+" ",
+#endif /* CK_AUTHENTICATION */
+#ifdef COMMENT
+"SET TELNET BINARY-MODE { ACCEPTED, REFUSED, REQUESTED, REQUIRED }",
+"  ACCEPT or REFUSE binary-mode bids, or actively REQUEST binary mode.",
+"  REQUIRED refuses the connection if binary mode is not successfully",
+"  negotiated in both directions.  ACCEPTED by default.",
+" ",
+#endif /* COMMENT */
+"SET TELNET BINARY-TRANSFER-MODE { ON, OFF }",
+"  When ON (OFF by default) and BINARY negotiations are not REFUSED Kermit",
+"  will attempt to negotiate BINARY mode in each direction before the start",
+"  of each file transfer.  After the transfer is complete BINARY mode will",
+"  be restored to the pre-transfer state.",
+" ",
+"SET TELNET BINARY-TRANSFER-MODE { ON, OFF }",
+"  Set this command to ON if you want to force Kermit to negotiate",
+"  Telnet Binary in both directions when performing file transfers.",
+"  Default is OFF.  Alias SET TELNET BINARY-XFER-MODE.",
+" ",
+"SET TELNET BUG AUTH-KRB5-DES { ON, OFF }",
+"  Default is ON.  Disable this bug to enable the use of encryption types",
+"  other than DES such as 3DES or CAST-128 when the Kerberos 5 session key",
+"  is longer than 8 bytes.",
+" ",
+"SET TELNET BUG BINARY-ME-MEANS-U-TOO { ON, OFF }",
+"  Set this to ON to try to overcome TELNET binary-mode misnegotiations by",
+"  Kermit's TELNET partner.",
+" ",
+"SET TELNET BUG BINARY-U-MEANS-ME-TOO { ON, OFF }",
+"  Set this to ON to try to overcome TELNET binary-mode misnegotiations by",
+"  Kermit's TELNET partner.",
+" ",
+"SET TELNET BUG INFINITE-LOOP-CHECK { ON, OFF }",
+"  Set this to ON to prevent Kermit from responding to a telnet negotiation",
+"  sequence that enters an infinite loop.  The default is OFF because this",
+"  should never occur.",
+" ",
+"SET TELNET BUG SB-IMPLIES-WILL-DO { ON, OFF }",
+"  Set this to ON to allow Kermit to respond to telnet sub-negotiations if",
+"  the peer forgets to respond to WILL with DO or to DO with WILL.",
+" ",
+"SET TELNET DEBUG { ON, OFF }",
+"  Set this to ON to display telnet negotiations as they are sent and",
+"  received.",
+" ",
+"SET TELNET DELAY-SB { ON, OFF }",
+"  When ON, telnet subnegotiation responses are delayed until after all",
+"  authentication and encryption options are either successfully negotiated",
+"  or refused. This ensures that private data is protected.  When OFF, telnet",
+"  subnegotiation responses are sent immediately.  The default is ON.",
+" ",
+"SET TELNET ECHO { LOCAL, REMOTE }",
+"  Kermit's initial echoing state for TELNET connections, LOCAL by default.",
+"  After the connection is made, TELNET negotiations determine the echoing.",
+" ",
+#ifdef CK_ENCRYPTION
+#ifdef COMMENT
+"SET TELNET ENCRYPTION { ACCEPTED, REFUSED, REQUESTED, REQUIRED }",
+"  ACCEPT or REFUSE encryption bids, or actively REQUEST encryption in both.",
+"  directions.  REQUIRED refuses the connection if encryption is not",
+"  successfully negotiated in both directions.  ACCEPTED by default.",
+" ",
+#endif /* COMMENT */
+"SET TELNET ENCRYPTION TYPE { AUTOMATIC, CAST128_CFB64, CAST128_OFB64, ",
+"  CAST5_40_CFB64, CAST5_40_OFB64, DES_CFB64, DES_OFB64, NONE }",
+"  AUTOMATIC allows the host to choose the preferred type of encryption.",
+"  Other values allow a specific encryption method to be specified.",
+"  AUTOMATIC is the default.  The list of options will vary depending",
+"  on the encryption types selected at compilation time.",
+" ",
+#endif /* CK_ENCRYPTION */
+#ifdef CK_ENVIRONMENT
+#ifdef COMMENT
+"SET TELNET ENVIRONMENT { ON, OFF, variable-name [ value ] }",
+"  This feature lets Kermit send the values of certain environment variables",
+"  to the other computer if it asks for them.  The variable-name can be any",
+"  of the \"well-known\" variables \"USER\", \"JOB\", \"ACCT\", \"PRINTER\",",
+"  \"SYSTEMTYPE\", or \"DISPLAY\".  Some Telnet servers, if given a USER",
+"  value in this way, will accept it and therefore not prompt you for user",
+"  name when you log in.  The default values are taken from your environment;",
+"  use this command to change or remove them.  See RFC1572 for details.  You",
+"  may also specify OFF to disable this feature, and ON to re-enable it.",
+" ",
+#else
+"SET TELNET ENVIRONMENT { variable-name [ value ] }",
+"  This feature lets Kermit send the values of certain environment variables",
+"  to the other computer if it asks for them.  The variable-name can be any",
+"  of the \"well-known\" variables \"USER\", \"JOB\", \"ACCT\", \"PRINTER\",",
+"  \"SYSTEMTYPE\", or \"DISPLAY\".  Some Telnet servers, if given a USER",
+"  value in this way, will accept it and therefore not prompt you for user",
+"  name when you log in.  The default values are taken from your environment;",
+"  use this command to change or remove them.  See RFC1572 for details.",
+" ",
+#endif /* COMMENT */
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_FORWARD_X
+"SET TELNET FORWARD-X XAUTHORITY-FILE <file>",
+"  If your X Server requires X authentication and the location of the",
+"  .Xauthority file is not defined by the XAUTHORITY environment variable,",
+"  use this command to specify the location of the .Xauthority file."
+"  ",
+#endif /* CK_FORWARD_X */
+#ifdef CK_SNDLOC
+"SET TELNET LOCATION [ text ]",
+"  Location string to send to the Telnet server if it asks.  By default this",
+"  is picked up from the LOCATION environment variable.  Give this command",
+"  with no text to disable this feature.",
+" ",
+#endif /* CK_SNDLOC */
+"SET TELNET NEWLINE-MODE { NVT, BINARY-MODE } { OFF, ON, RAW }",
+
+"  Determines how carriage returns are handled on TELNET connections.  There",
+"  are separate settings for NVT (ASCII) mode and binary mode.  ON (default",
+"  for NVT mode) means CRLF represents CR.  OFF means CR followed by NUL",
+"  represents CR.  RAW (default for BINARY mode) means CR stands for itself.",
+" ",
+#ifdef TCPSOCKET
+"SET TELNET PROMPT-FOR-USERID <prompt>",
+"  Specifies a custom prompt to be used when prompting for a userid.  Kermit",
+"  prompts for a userid if the command:",
+" ",
+"    SET LOGIN USERID {}",
+" ",
+"  has been issued prior to a Telnet authentication negotiation for an",
+"  authentication type that requires the transmission of a name, such as",
+"  Secure Remote Password.",
+" ",
+#endif /* TCPSOCKET */
+"SET TELNET REMOTE-ECHO { ON, OFF }",
+"  Applies only to incoming connections created with:",
+"    SET HOST * <port> /TELNET",
+"  This command determines whether Kermit will actually echo characters",
+"  received from the remote when it has negotiated to do so.  The default",
+"  is ON.  Remote echoing may be turned off when it is necessary to read",
+"  a password with the INPUT command.",
+" ",
+"SET TELNET TERMINAL-TYPE name",
+"  The terminal type to send to the remote TELNET host.  If none is given,",
+#ifdef OS2
+"  your current SET TERMINAL TYPE value is sent, e.g. VT220.",
+" ",
+#else
+"  your local terminal type is sent.",
+" ",
+#endif /* OS2 */
+"SET TELNET WAIT-FOR-NEGOTIATIONS { ON, OFF }",
+"  Each Telnet option must be fully negotiated either On or Off before the",
+"  session can continue.  This is especially true with options that require",
+"  subnegotiations such as Authentication, Encryption, and Kermit; for",
+"  proper support of these options Kermit must wait for the negotiations to",
+"  complete.  Of course, Kermit has no way of knowing whether a reply is",
+"  delayed or not coming at all, and so will wait a minute or more for",
+"  required replies before continuing the session.  If you know that Kermit's",
+"  Telnet partner will not be sending the required replies, you can set this",
+"  option of OFF to avoid the long timeouts.  Or you can instruct Kermit to",
+"  REFUSE specific options with the SET TELOPT command.",
+"",
+"Type SHOW TELNET to see the current values of these parameters.",
+"" };
+#endif /* TNCODE */
+
+#ifndef NOSPL
+static char *hxymacr[] = {
+"Syntax: SET MACRO parameter value",
+"  Controls the behavior of macros.",
+" ",
+"SET MACRO ECHO { ON, OFF }",
+"  Tells whether commands executed from a macro definition should be",
+"  displayed on the screen.  OFF by default; use ON for debugging.",
+" ",
+"SET MACRO ERROR { ON, OFF }",
+"  Tells whether a macro should be automatically terminated upon a command",
+"  error.  This setting is local to the current macro, and inherited by",
+"  subordinate macros.",
+"" };
+#endif /* NOSPL */
+
+static char *hmxyprm[] = {
+"Syntax: SET PROMPT [ text ]",
+" ",
+#ifdef OS2
+"Prompt text for this program, normally 'K-95>'.  May contain backslash",
+#else
+#ifdef MAC
+"Prompt text for this program, normally 'Mac-Kermit>'.  May contain backslash",
+#else
+"Prompt text for this program, normally 'C-Kermit>'.  May contain backslash",
+#endif /* MAC */
+#endif /* OS2 */
+"codes for special effects.  Surround by { } to preserve leading or trailing",
+#ifdef OS2
+"spaces.  If text omitted, prompt reverts to K-95>.  Prompt can include",
+#else
+#ifdef MAC
+"spaces.  If text omitted, prompt reverts to Mac-Kermit>.  Prompt can include",
+#else
+"spaces.  If text omitted, prompt reverts to C-Kermit>.  Prompt can include",
+#endif /* OS2 */
+#endif /* MAC */
+"variables like \\v(dir) or \\v(time) to show current directory or time.",
+"" };
+
+#ifdef UNIX
+static char *hxywild[] = {
+"Syntax: SET WILDCARD-EXPANSION { KERMIT [ switch ], SHELL }",
+"  KERMIT (the default) means C-Kermit expands filename wildcards in SEND and",
+"  similar commands itself, and in incoming GET commands.  Optional switches",
+"  are /NO-MATCH-DOT-FILES (\"*\" and \"?\" should not match in initial",
+"  period in a filename; this is the default) and /MATCH-DOT-FILES if you",
+"  want files whose names begin with \".\" included.  SET WILDCARD SHELL",
+"  means that Kermit asks your preferred shell to expand wildcards (this",
+"  should not be necessary in C-Kermit 7.0 and later).  HELP WILDCARD for",
+"  further information.",
+"" };
+#endif /* UNIX */
+
+#ifndef NOXFER
+static char *hxywind[] = {
+"Syntax: SET WINDOW-SIZE number",
+"  Specifies number of slots for sliding windows, i.e. the number of packets",
+"  that can be transmitted before waiting for acknowledgement.  The default",
+#ifdef XYZ_INTERNAL
+"  for Kermit protocol is one, the maximum is 32; for ZMODEM, the default",
+"  is no windowing (0).  For ZMODEM, the window size is really the packet",
+"  length, and is used only when non-windowed (streaming) transfers fail; the",
+"  ZMODEM window size should be a largish number, like 1024, and it should be",
+"  a multiple of 64.",
+#else
+"  is one, the maximum is 32.  Increased window size might result in reduced",
+"  maximum packet length.  Use sliding windows for improved efficiency on",
+"  connections with long delays.  A full duplex connection is required, as",
+"  well as a cooperating Kermit on the other end.",
+#endif /* XYZ_INTERNAL */
+"" };
+
+static char *hxyrpt[] = {
+"Syntax: SET REPEAT { COUNTS { ON, OFF }, PREFIX <code> }",
+"  SET REPEAT COUNTS turns the repeat-count compression mechanism ON and OFF.",
+"  The default is ON.  SET REPEAT PREFIX <code> sets the repeat-count prefix",
+"  character to the given code.  The default is 126 (tilde).",
+"" };
+
+static char *hxyrcv[] = {
+"Syntax: SET RECEIVE parameter value",
+"  Specifies parameters for inbound packets:",
+" ",
+#ifndef NOCSETS
+"SET RECEIVE CHARACTER-SET { AUTOMATIC, MANUAL }",
+"  Whether to automatically switch to an appropriate file-character set based",
+"  on the transfer character-set announcer, if any, of an incoming text file.",
+"  AUTOMATIC by default.  Also see HELP ASSOCIATE.",
+" ",
+#endif /* NOCSETS */
+"SET RECEIVE CONTROL-PREFIX number",
+"  ASCII value of prefix character used for quoting control characters in",
+"  packets that Kermit receives, normally 35 (number sign).  Don't change",
+"  this unless something is wrong with the other Kermit program.",
+" ",
+"SET RECEIVE END-OF-PACKET number",
+"  ASCII value of control character that terminates incoming packets,",
+"  normally 13 (carriage return).",
+" ",
+#ifdef CKXXCHAR
+"SET RECEIVE IGNORE-CHARACTER number",
+"  ASCII value of character to be discarded when receiving packets, such as",
+"  line folding characters.",
+" ",
+#endif /* CKXXCHAR */
+"SET RECEIVE MOVE-TO [ directory ]",
+"  If a directory name is specified, then every file that is received",
+"  successfully is moved to the given directory immediately after reception",
+"  is complete.  Omit the directory name to remove any previously set move-to",
+"  directory.",
+" ",
+"SET RECEIVE PACKET-LENGTH number",
+"  Maximum length packet the other Kermit should send.",
+" ",
+"SET RECEIVE PADDING number",
+"  Number of prepacket padding characters to ask for (normally 0).",
+" ",
+"SET RECEIVE PAD-CHARACTER number",
+"  ASCII value of control character to use for padding (normally 0).",
+" ",
+"SET RECEIVE PATHNAMES {OFF, ABSOLUTE, RELATIVE, AUTO}",
+"  If a recognizable path (directory, device) specification appears in an",
+"  incoming filename, strip it OFF before trying to create the output file.",
+#ifdef CK_MKDIR
+"  Otherwise, then if any of the directories in the path don't exist, Kermit",
+"  tries to create them, relative to your current or download directory, or",
+"  absolutely, as specified.  RELATIVE means force all incoming names, even",
+"  if they are absolute, to be relative to your current or download directory."
+,
+"  AUTO, which is the default, means RELATIVE if the file sender indicates in",
+"  advance that this is a recursive transfer, otherwise OFF.",
+#endif /* CK_MKDIR */
+" ",
+"SET RECEIVE PAUSE number",
+"  Milliseconds to pause between packets, normally 0.",
+" ",
+
+#ifdef CK_PERMS
+"SET RECEIVE PERMISSIONS { ON, OFF }",
+"  Whether to copy file permissions from inbound Attribute packets.",
+" ",
+#endif /* CK_PERMS */
+
+"SET RECEIVE RENAME-TO [ template ]",
+"  If a template is specified, then every file that is received successfully",
+"  \
+is renamed according to the given template immediately after it is received.",
+"  \
+The template should include variables like \\v(filename) or \\v(filenumber).",
+"  Omit the template to remove any template previously set.",
+" ",
+"SET RECEIVE START-OF-PACKET number",
+"  ASCII value of character that marks start of inbound packet.",
+" ",
+"SET RECEIVE TIMEOUT number",
+"  Number of seconds the other Kermit should wait for a packet before sending",
+"  a NAK or retransmitting.",
+#ifdef VMS
+" ",
+"SET RECEIVE VERSION-NUMBERS { ON, OFF }",
+"  If ON, and in incoming filename includes a VMS version number, use it when",
+"  creating the file.  If OFF (which is the default), strip any VMS version",
+"  number from incoming filenames before attempting to create the file, \
+causing",
+"  the new file to receive the next highest version number.",
+#endif /* VMS */
+"" };
+
+static char *hxysnd[] = {
+"Syntax: SET SEND parameter value",
+"  Specifies parameters for outbound files or packets.",
+" ",
+"SET SEND BACKUP { ON, OFF }",
+"  Tells whether to include backup files when sending file groups.  Backup",
+"  files are those created by Kermit, EMACS, etc, when creating a new file",
+"  that has the same name as an existing file.  A backup file has a version",
+"  appended to its name, e.g. oofa.txt.~23~.  ON is the default, meaning",
+"  don't exclude backup files.  Use OFF to exclude backup files from group",
+"  transfers.",
+" ",
+#ifndef NOCSETS
+"SET SEND CHARACTER-SET { AUTOMATIC, MANUAL }",
+"  Whether to automatically switch to an appropriate file-character when a",
+"  SET TRANSFER CHARACTER-SET command is given, or vice versa.  AUTOMATIC by",
+"  default.  Also see HELP ASSOCIATE.",
+" ",
+#endif /* NOCSETS */
+
+"SET SEND CONTROL-PREFIX number",
+"  ASCII value of prefix character used for quoting control characters in",
+"  packets that Kermit sends, normally 35 (number sign).",
+" ",
+#ifdef CKXXCHAR
+"SET SEND DOUBLE-CHARACTER number",
+"  ASCII value of character to be doubled when sending packets, such as an",
+"  X.25 PAD escape character.",
+" ",
+#endif /* CKXXCHAR */
+"SET SEND END-OF-PACKET number",
+"  ASCII value of control character to terminate an outbound packet,",
+"  normally 13 (carriage return).",
+" ",
+"SET SEND MOVE-TO [ directory ]",
+"  \
+If a directory name is specified, then every file that is sent successfully",
+"  is moved to the given directory immediately after it is sent.",
+"  Omit the directory name to remove any previously set move-to directory.",
+" ",
+"SET SEND PACKET-LENGTH number",
+"  Maximum length packet to send, even if other Kermit asks for longer ones.",
+"  This command can not be used to force packets to be sent that are longer",
+"  than the length requested by the receiver.  Use this command only to",
+"  force shorter ones.",
+" ",
+"SET SEND PADDING number",
+"  Number of prepacket padding characters to send.",
+" ",
+"SET SEND PAD-CHARACTER number",
+"  ASCII value of control character to use for padding.",
+" ",
+"SET SEND PATHNAMES {OFF, ABSOLUTE, RELATIVE}",
+"  Include the path (device, directory) portion with the file name when",
+"  sending it as specified; ABSOLUTE means to send the whole pathname,",
+"  RELATIVE means to include the pathname relative to the current directory.",
+"  Applies to the actual filename, not to the \"as-name\".  The default is",
+"  OFF.",
+" ",
+"SET SEND PAUSE number",
+"  Milliseconds to pause between packets, normally 0.",
+" ",
+
+#ifdef CK_PERMS
+"SET SEND PERMISSIONS { ON, OFF }",
+"  Whether to include file permissions in outbound Attribute packets.",
+" ",
+#endif /* CK_PERMS */
+
+"SET SEND RENAME-TO [ template ]",
+"  If a template is specified, then every file that is sent successfully",
+"  is renamed according to the given template immediately after it is sent.",
+"  \
+The template should include variables like \\v(filename) or \\v(filenumber).",
+"  Omit the template to remove any template previously set.",
+" ",
+"SET SEND START-OF-PACKET number",
+"  ASCII value of character to mark start of outbound packet.",
+" ",
+#ifdef CK_TIMERS
+"SET SEND TIMEOUT number [ { DYNAMIC [ min max ] ], FIXED } ]",
+#else
+"SET SEND TIMEOUT number",
+#endif /* CK_TIMERS */
+
+"  Number of seconds to wait for a packet before sending NAK or",
+#ifdef CK_TIMERS
+"  retransmitting.  Include the word DYNAMIC after the number in the",
+"  SET SEND TIMEOUT command to have Kermit compute the timeouts dynamically",
+"  throughout the transfer based on the packet rate.  Include the word FIXED",
+"  to use the \"number\" given throughout the transfer.  DYNAMIC is the",
+"  default.  After DYNAMIC you may include minimum and maximum values.",
+#else
+"  retransmitting.",
+#endif /* CK_TIMERS */
+#ifdef VMS
+" ",
+"SET SEND VERSION-NUMBERS { ON, OFF }",
+"  If ON, include VMS version numbers in outbound filenames.  If OFF (which",
+"  is the default), strip version numbers.",
+#endif /* VMS */
+"" };
+
+static char *hxyxfer[] = {
+"Syntax: SET TRANSFER (or XFER) paramater value",
+" ",
+"Choices:",
+" ",
+"SET TRANSFER BELL { OFF, ON }",
+"  Whether to ring the terminal bell at the end of a file transfer.",
+" ",
+#ifdef XFRCAN
+"SET TRANSFER CANCELLATION { OFF, ON [ <code> [ <number> ] ] }",
+"  OFF disables remote-mode packet-mode cancellation from the keyboard.",
+"  ON enables it.  The optional <code> is the control character to use for",
+"  cancellation; the optional <number> is how many consecutive occurrences",
+"  of the given control character are required for cancellation.",
+" ",
+#endif /* XFRCAN */
+"SET TRANSFER INTERRUPTION { ON, OFF }",
+"  TRANSFER INTERRUPTION is normally ON, allowing for interruption of a file",
+"  transfer in progress by typing certain characters while the file-transfer",
+"  display is active.  SET TRANSFER INTERRUPTION OFF disables interruption",
+"  of file transfer from the keyboard in local mode.",
+" ",
+#ifndef NOSPL
+"SET TRANSFER CRC-CALCULATION { OFF, ON }",
+"  Tells whether Kermit should accumulate a Cyclic Redundancy Check for ",
+"  each file transfer.  Normally ON, in which case the CRC value is available",
+"  in the \\v(crc16) variable after the transfer.  Adds some overhead.  Use",
+"  SET TRANSFER CRC OFF to disable.",
+" ",
+#endif /* NOSPL */
+#ifndef NOCSETS
+"SET TRANSFER CHARACTER-SET name",
+"  Selects the character set used to represent textual data in Kermit",
+"  packets.  Text characters are translated to/from the FILE CHARACTER-SET.",
+"  Choices:",
+" ",
+"  TRANSPARENT (no translation, the default)",
+"  ASCII",
+"  LATIN1 (ISO 8859-1 Latin Alphabet 1)",
+#ifndef NOLATIN2
+"  LATIN2 (ISO 8859-2 Latin Alphabet 2)",
+#endif /* NOLATIN2 */
+"  LATIN9 (ISO 8859-15 Latin Alphabet 9)",
+#ifdef CYRILLIC
+"  CYRILLIC-ISO (ISO 8859-5 Latin/Cyrillic)",
+#endif /* CYRILLIC */
+#ifdef GREEK
+"  GREEK-ISO (ISO 8859-7 Latin/Greek)",
+#endif /* GREEK */
+#ifdef HEBREW
+"  HEBREW-ISO (ISO 8859-8 Latin/Hebrew)",
+#endif /* HEBREW */
+#ifdef KANJI
+"  JAPANESE-EUC (JIS X 0208 Kanji + Roman and Katakana)",
+#endif /* KANJI */
+#ifdef UNICODE
+"  UCS-2 (ISO 10646 / Unicode 2-byte form)",
+"  UTF-8 (ISO 10646 / Unicode 8-bit serialized transformation format)",
+#endif /* UNICODE */
+" ",
+"SET TRANSFER TRANSLATION { ON, OFF }",
+"  Enables and disables file-transfer character-set translation.  It's",
+"  enabled by default.",
+#endif /* NOCSETS */
+" ",
+#ifdef CK_CURSES
+"SET TRANSFER DISPLAY { BRIEF, CRT, FULLSCREEN, NONE, SERIAL }",
+#else
+"SET TRANSFER DISPLAY { BRIEF, CRT, NONE, SERIAL }",
+#endif  /* CK_CURSES */
+"  Choose the desired format for the progress report to be displayed on",
+"  your screen during file transfers when Kermit is in local mode.",
+#ifdef CK_CURSES
+"  FULLSCREEN requires your terminal type be set correctly; the others",
+"  are independent of terminal type.",
+#else
+"  file transfer.",
+#endif  /* CK_CURSES */
+" ",
+"SET TRANSFER LOCKING-SHIFT { OFF, ON, FORCED }",
+"  Tell whether locking-shift protocol should be used during file transfer",
+"  to achieve 8-bit transparency on a 7-bit connection.  ON means to request",
+"  its use if PARITY is not NONE and to use it if the other Kermit agrees,",
+"  OFF means not to use it, FORCED means to use it even if the other Kermit",
+"  does not agree.",
+" ",
+"SET TRANSFER MODE { AUTOMATIC, MANUAL }",
+"  Automatic (the default) means Kermit should automatically go into binary",
+"  file-transfer mode and use literal filenames if the other Kermit says it",
+"  has a compatible file system, e.g. UNIX-to-UNIX, but not UNIX-to-DOS.",
+#ifdef PATTERNS
+"  Also, when sending files, Kermit should switch between binary and text",
+"  mode automatically per file based on the SET FILE BINARY-PATTERNS and SET",
+"  FILE TEXT-PATTERNS.",
+#endif /* PATTERNS */
+" ",
+#ifdef PIPESEND
+"SET TRANSFER PIPES { ON, OFF }",
+"  Enables/Disables automatic sending from / reception to command pipes when",
+"  the incoming filename starts with '!'.  Also see CSEND, CRECEIVE.",
+" ",
+#endif /* PIPESEND */
+#ifdef CK_XYZ
+"SET TRANSFER PROTOCOL { KERMIT, XMODEM, ... }",
+"  Synonym for SET PROTOCOL (q.v.).",
+" ",
+#endif /* CK_XYZ */
+"SET TRANSFER REPORT { ON, OFF }",
+"  Enables/Disables the automatic post-transfer message telling what files",
+"  went where from C-Kermit when it is in remote mode.  ON by default.",
+" ",
+"SET TRANSFER SLOW-START { OFF, ON }",
+"  ON (the default) tells Kermit, when sending files, to gradually build up",
+"  the packet length to the maximum negotiated length.  OFF means start",
+"  sending the maximum length right away.",
+" ",
+"Synonym: SET XFER.  Use SHOW TRANSFER (XFER) to see SET TRANSFER values.",
+"" };
+#endif /* NOXFER */
+
+#ifdef NT
+static char *hxywin95[] = {
+"SET WIN95 8.3-FILENAMES { ON, OFF }",
+"  Instructs K-95 to report all filenames using 8.3 notation instead of the",
+"  normal long filenames.  Default is OFF",
+" ",
+"SET WIN95 ALT-GR { ON, OFF }",
+"  Instructs K-95, when used on MS Windows 95, to interpret the Right Alt key",
+"  as the Alt-Gr key.  This is necessary to work around the failure of",
+"  Windows 95 to properly translate non-US keyboards.  Default is OFF.",
+" ",
+"SET WIN95 KEYBOARD-TRANSLATION <character-set>",
+"  Specifies the character-set that Windows 95 is using to send keystrokes",
+"  to Kermit-95 via the keyboard input functions.  Default is Latin1-ISO.",
+" ",
+"SET WIN95 OVERLAPPED-IO { ON <requests>, OFF }",
+"  Determines whether or not K-95 uses Overlapped-I/O methods for reading",
+"  from and writing to serial and TAPI communication devices.  <requests>",
+"  specifies the maximum number of simultaneous write requests that may be",
+"  overlapped, from 1 to 30.  Default is ON.",
+" ",
+"SET WIN95 POPUPS { ON, OFF }",
+"  Determines whether or not Kermit 95 uses Popups to query the user for",
+"  necessary information such as user IDs or passwords.  Default is ON.",
+" ",
+"SET WIN95 SELECT-BUG { ON, OFF }"
+"  Some TCP/IP (Winsock) implementations for Windows have a defective",
+"  select() function.  Use this command to avoid the use of select() if",
+"  K95 appears to be unable to send data over TCP/IP.  Default is OFF.",
+""};
+#endif /* NT */
+
+static char *hmxybel[] = {
+#ifdef OS2
+"Syntax: SET BELL { AUDIBLE [ { BEEP, SYSTEM-SOUNDS } ], VISIBLE, NONE }",
+"  Specifies how incoming Ctrl-G (bell) characters are handled in CONNECT",
+"  mode and how command warnings are presented in command mode.  AUDIBLE",
+"  means either a beep or a system-sound is generated; VISIBLE means the",
+"  screen is flashed momentarily.",
+#else
+"Syntax: SET BELL { OFF, ON }",
+"  ON (the default) enables ringing of the terminal bell (beep) except where",
+"  it is disabled in certain circumstances, e.g. by SET TRANSFER BELL.  OFF",
+"  disables ringing of the bell in all circumstances, overriding any specific",
+"  SET xxx BELL selections.",
+#endif /* OS2 */
+""};
+
+static char *hmxycd[] = {
+"Syntax: SET CD { HOME <path>, PATH <path>, MESSAGE { ON, OFF, FILE <list> } }"
+,
+" ",
+"SET CD HOME <path>",
+"  Specified which directory to change to if CD or KCD is given without a",
+"  pathname.  If this command is not given, your login or HOME directory is",
+"  used.",
+" ",
+"SET CD PATH <path>",
+"  Overrides normal CDPATH environment variable, which tells the CD command",
+"  where to look for directories to CD to if you don't specify them fully.",
+"  The format is:",
+" ",
+#ifdef UNIXOROSK
+"    set cd path :directory:directory:...",
+" ",
+"  in other words, a list of directories separated by colons, with a colon",
+"  at the beginning, e.g.:",
+" ",
+"    set cd path :/usr/olga:/usr/ivan/public:/tmp",
+#else
+#ifdef OS2
+"    set cd path disk:directory;disk:directory;...",
+" ",
+"  just like the DOS PATH; in other words, a list of disk:directory names",
+"  separated by semicolons, e.g.:",
+" ",
+"    SET CD PATH C:\\K95;C:\\HOME;C:\\LOCAL;C:\\",
+#else
+#ifdef VMS
+"    set cd path directory,directory,...",
+" ",
+"  in other words, a list of directory specifications or logical names that",
+"  represent them, e.g.:",
+" ",
+"    SET CD PATH SYS$LOGIN:,$DISK1:[OLGA],$DISK2[SCRATCH.IVAN].",
+#else
+"  (unknown for this platform)",
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIXOROSK */
+" ",
+"SET CD MESSAGE { ON, OFF }",
+"  Default is OFF.  When ON, this tells Kermit to look for a file with a",
+"  certain name in any directory that you CD to, and if it finds one, to",
+"  display it on your screen when you give the CD command.  The filename,",
+"  or list of names, is given in the SET CD MESSAGE FILE command.",
+" ",
+"SET CD MESSAGE FILE name",
+"  or:",
+"SET CD MESSAGE FILE {{name1}{name2}...{name8}}",
+"  Specify up to 8 filenames to look for when when CDing to a new directory",
+"  and CD MESSAGE is ON.  The first one found, if any, in the new directory",
+#ifndef DFCDMSG
+"  is displayed.",
+#else
+"  is displayed.  The default list is:",
+" ",
+#ifdef UNIXOROSK
+"   {{./.readme}{README.TXT}{READ.ME}}",
+#else
+"   {{README.TXT}{READ.ME}}",
+#endif /* UNIXOROSK */
+" ",
+#endif /* DFCDMSG */
+#ifndef NOSERVER
+"Synonym: SET SERVER CD-MESSAGE FILE.",
+#endif /* NOSERVER */
+" ",
+"Type SHOW CD to view current CD settings.  Also see HELP SET SERVER.",
+""
+};
+
+#ifndef NOIKSD
+static char * hsetiks[] = {
+#ifdef OS2
+"SET IKS ANONYMOUS ACCOUNT <username>",
+"  On Windows NT/2000 this is the account that will be used to allow",
+"  anonymous access to the system.  This account MUST have no password",
+"  and its privileges should be restricted to only allow those operations",
+"  which should be permitted to unknown users.  In practice this means",
+"  List Directories and Read-Execute privileges only.  If a directory",
+"  is configured for Write privileges then Read privileges should be",
+"  denied for that directory.  Otherwise, your system will become used",
+"  by software pirates.  If this command is not specified in the IKSD.KSC",
+"  file the username \"GUEST\" is used by default.  This command has no",
+"  effect on Windows 95/98.",
+" ",
+#endif /* OS2 */
+"SET IKS ANONYMOUS INITFILE filename",
+#ifdef OS2
+"  The initialization file to be executed for anonymous logins.  By default",
+"  it is K95.INI in the home directory associated with the ANNONYMOUS account."
+,
+"  Any filename that you specify here must be readable by the ANONYMOUS",
+"  account and if a SET IKS ANONYMOUS ROOT command was given, exist within",
+"  the restricted directory tree.  This option is independent of the SET IKS",
+"  INITFILE command which applies only to real users.",
+#else
+"  The initialization file to be executed for anonymous logins.  By default",
+"  it is .kermrc in the anonymous root directory.  This option is independent",
+"  of the SET IKS INITFILE command which applies only to real users.",
+#endif /* OS2 */
+" ",
+"SET IKS ANONYMOUS LOGIN { ON, OFF }",
+#ifdef OS2
+"  Whether anonymous logins are allowed.  By default they are NOT allowed,",
+"  so this option need be included only to allow them (or for clarity, to",
+"  emphasize that they are not allowed).  Anonymous login occurs when the",
+"  username \"anonymous\" is specified with any password (as with ftpd).",
+"  In order for anonymous logins to succeed on Windows NT/2000, the",
+"  ANONYMOUS account must be enabled.",
+" ",
+"  On Windows NT and 2000, anonymous users have the same access rights as",
+"  the ANONYMOUS account.  In Windows 95/98, anonymous users, just like any",
+"  other users, have full access rights to your entire PC, since Windows 95",
+"  and 98 include no security features.  For this reason, if you are allowing",
+"  anonymous logins, be sure to also SET an IKS ANONYMOUS ROOT directory to",
+"  restrict anonymous users' file access.",
+" ",
+"  Anonymous user permissions may be restricted via the specification of ",
+"  DISABLE commands in the ANONYMOUS initfile.  Anonymous users are not ",
+"  permitted to execute an ENABLE command.  Anonymous users are also prevented"
+,
+"  from SHOWing sensitive data about the operating system or the IKS",
+"  configuration.",
+#else
+"  Whether anonymous logins are allowed. By default they are allowed, so this",
+"  option need be included only to disallow them (or for clarity, to emphasize"
+,
+"  they are allowed). Anonymous login occurs when the username \"anonymous\"",
+"  or \"ftp\" is given, with any password (as with ftpd).",
+#endif /* OS2 */
+" ",
+"SET IKS ANONYMOUS ROOT <directory>",
+"  Specifies a directory tree to which anonymous users are restricted after",
+"  login.",
+" ",
+"SET IKS BANNERFILE <filename>",
+"  The name of a file containing a message to be printed after the user logs",
+"  in, in place of the normal message (copyright notice, \"Type HELP or ? for",
+"  help\", etc).",
+" ",
+"SET IKS CDFILE <filelist>",
+"  When cdmessage is on, this is the name of the \"read me\" file to be shown."
+,
+"  Normally you would specify a relative (not absolute) name, since the file",
+"  is opened using the literal name you specified, after changing to the new",
+"  directory.  Example:",
+" ",
+"    SET IKS CDFILE READ.ME",
+" ",
+"  You can also give a list of up to 8 filenames by (a) enclosing each",
+"  filename in braces, and (b) enclosing the entire list in braces.  Example:",
+" ",
+"    SET IKS CDFILE {{READ.ME}{aareadme.txt}{README}{read-this-first}}",
+" ",
+"  When a list is given, it is searched from left to right and the first",
+"  file found is displayed.",
+" ",
+"SET IKS CDMESSAGE {ON, OFF, 0, 1, 2}",
+"  For use in the Server-Side Server configuration; whenever the client",
+"  tells the server to change directory, the server sends the contents of a",
+"  \"read me\" file to the client's screen.  This feature is ON by default,",
+"  and operates in client/server mode only when ON or 1.  If set to 2 or",
+"  higher, it also operates when the CD command is given at the IKSD> prompt.",
+"  Synonym: SET IKS CDMSG.",
+" ",
+"SET IKS DATABASE { ON, OFF }",
+"  This command determines whether entries are inserted into the SET IKS",
+"  DBFILE (IKSD active sessions database).",
+" ",
+"SET IKS DBFILE <filename>",
+"  Specifies the file which should be used for storing runtime status",
+#ifdef OS2
+"  information about active connections.  The default is a file called",
+"  \"iksd.db\" in the WINDOWS directory.",
+#else
+#ifdef UNIX
+"  information about active connections.  The default is a file called",
+"  \"iksd.db\" in the /var/log directory.",
+#else
+"  information about active connections.",
+#endif /* UNIX */
+#endif /* OS2 */
+" ",
+#ifdef OS2
+"SET IKS DEFAULT-DOMAIN <domain-name>",
+"  A userid on Windows is of the form DOMAIN\\\\userid.  This command",
+"  determines which domain will be searched for the userid if a domain",
+"  is not specified by the user.  On Windows 95/98 when User-level",
+"  access is activated in the Network Control Panel, the default ",
+"  domain will be automatically set.  If the default domain is not",
+"  specified, accounts on the local machine will take precedence over",
+"  accounts in Domains to which the local machine belongs.",
+#endif /* OS2 */
+" ",
+"SET IKS HELPFILE <filename>",
+"  Specifies the name of a file to be displayed if the user types HELP",
+"  (not followed by a specific command or topic), in place of the built-in",
+"  top-level help text.  The file need not fit on one screen; more-prompting",
+"  is used if the file is more than one screen long if COMMAND MORE-PROMPTING",
+"  is ON, as it is by default.",
+" ",
+"SET IKS INITFILE <filename>",
+"  Execute <filename> rather than the normal initialization file for real",
+"  users; this option does not apply to anonymous users.",
+" ",
+"SET IKS NO-INITFILE { ON, OFF }",
+"  Do not execute an initialization file, even if a real user is logging in.",
+" ",
+"SET IKS SERVER-ONLY { ON, OFF }",
+"  If this option is included on the IKSD command line, the Client Side Server"
+,
+"  configuration is disabled, and the user will not get a Username: or",
+"  Password: prompt, and will not be able to access the IKSD command prompt.",
+"  A FINISH command sent to the IKSD will log it out and close the",
+"  connection, rather than returning it to its prompt.",
+" ",
+"SET IKS TIMEOUT <number>",
+"  This sets a limit (in seconds) on the amount of time the client has to log",
+"  in once the connection is made.  If successful login does not occur within",
+"  the given number of seconds, the connection is closed.  The default timeout"
+,
+"  is 300 seconds (5 minutes).  A value of 0 or less indicates there is to be",
+"  no limit.",
+" ",
+"SET IKS USERFILE <filename>",
+#ifdef UNIX
+"  This file contains a list of local usernames that are to be denied access",
+"  to Internet Kermit Service.  The default is /etc/ftpusers.  This can be the"
+,
+"  same file that is used by wuftpd, and the syntax is the same: one username",
+"  per line; lines starting with \"#\" are ignored.  Use this option to",
+"  specify the name of a different forbidden-user file, or use",
+"  \"set iks userfile /dev/null\" to disable this feature in case there is a",
+"   /etc/ftpusers file but you don't want to use it.",
+#else
+"  This file contains a list of local usernames that are to be denied access",
+"  to Internet Kermit Service.  The syntax is: one username per line; lines",
+"  starting with \"#\" are ignored.",
+#endif /* UNIX */
+" ",
+"SET IKS XFERLOG { ON, OFF }",
+#ifdef UNIX
+"  Whether a file-transfer log should be kept.  Off by default.  If \"on\",",
+"  but no SET IKSD XFERFILE command is given, /var/log/iksd.log is used.",
+#else
+"  Whether a file-transfer log should be kept.  Off by default.",
+#endif /* UNIX */
+" ",
+"SET IKS XFERFILE <filename>",
+"  Use this option to specify an iksd log file name.  If you include this",
+"  option, it implies SET IKS XFERFILE ON.",
+""
+};
+#endif /* NOIKSD */
+
+/*  D O H S E T  --  Give help for SET command  */
+
+int
+dohset(xx) int xx; {
+    int x;
+
+    if (xx == -3) return(hmsga(hmhset));
+    if (xx < 0) return(xx);
+
+#ifdef NEWFTP
+    if (xx == XYFTPX)
+      return(dosetftphlp());
+    if (xx == XYGPR)
+      return(hmsga(hmxygpr));
+#endif /* NEWFTP */
+
+    if ((x = cmcfm()) < 0) return(x);
+    switch (xx) {
+#ifndef NOIKSD
+      case XYIKS:
+        return(hmsga(hsetiks));
+#endif /* NOIKSD */
+
+case XYATTR:
+    return(hmsga(hsetat));
+
+case XYBACK:
+    return(hmsga(hsetbkg));
+
+case XYBELL:
+    return(hmsga(hmxybel));
+
+#ifdef OS2
+case XYPRTY:
+    return(hmsg("SET PRIORITY { REGULAR, FOREGROUND-SERVER, TIME-CRITICAL }\n\
+  Specifies at which priority level the communication and screen update\n\
+  threads should operate.  The default value is FOREGROUND-SERVER."));
+#endif /* OS2 */
+
+#ifdef DYNAMIC
+case XYBUF:
+    return(hmsga(hsetbuf));
+#endif /* DYNAMIC */
+
+#ifndef NOLOCAL
+case XYCARR:
+    return(hmsga(hsetcar));
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+case XYCASE:
+    return(hmsg("Syntax: SET CASE { ON, OFF }\n\
+  Tells whether alphabetic case is significant in string comparisons\n\
+  done by INPUT, IF, and other commands.  This setting is local to the\n\
+  current macro or command file, and inherited by subordinates."));
+
+#endif /* NOSPL */
+
+case XYCMD:
+    return(hmsga(hsetcmd));
+
+case XYIFD:
+    return(hmsg("Syntax: SET INCOMPLETE { DISCARD, KEEP }\n\
+  Whether to discard or keep incompletely received files, default is KEEP."));
+
+#ifndef NOSPL
+case XYINPU:
+    return(hmsga(hxyinp));
+#endif /* NOSPL */
+
+case XYCHKT:
+    return(hmsga(hmxychkt));
+
+#ifndef NOSPL
+case XYCOUN:
+    return(hmsg("Syntax:  SET COUNT number\n\
+ Example: SET COUNT 5\n\
+  Set up a loop counter, for use with IF COUNT.  Local to current macro\n\
+  or command file, inherited by subordinate macros and command files."));
+#endif /* NOSPL */
+
+case XYDEBU:
+    return(hmsga(hmxydeb));
+
+case XYDFLT:
+    return(hmsg("Syntax: SET DEFAULT directory\n\
+  Change directory.  Equivalent to CD command."));
+
+case XYDELA:
+    return(hmsg("Syntax: SET DELAY number\n\
+  Number of seconds to wait before sending first packet after SEND command."));
+
+#ifndef NODIAL
+case XYDIAL:
+    return(hmsga(hmxydial));
+#endif /* NODIAL */
+
+#ifdef UNIX
+case XYSUSP:
+    return(hmsg("Syntax: SET SUSPEND { OFF, ON }\n\
+  Disables SUSPEND command, suspend signals, and <esc-char>Z during CONNECT.")
+           );
+#endif
+
+#ifndef NOSCRIPT
+case XYSCRI:
+    return(hmsg("Syntax: SET SCRIPT ECHO { OFF, ON }\n\
+  Disables/Enables echoing of SCRIPT command operation."));
+#endif /* NOSCRIPT */
+
+case XYTAKE:
+    return(hmsga(hxytak));
+
+#ifndef NOLOCAL
+case XYTERM:
+    return(hmsga(hxyterm));
+
+case XYDUPL:
+    return(hmsg("Syntax: SET DUPLEX { FULL, HALF }\n\
+  During CONNECT: FULL means remote host echoes, HALF means Kermit\n\
+  does its own echoing."));
+
+case XYLCLE:
+    return(hmsg("Syntax: SET LOCAL-ECHO { OFF, ON }\n\
+  During CONNECT: OFF means remote host echoes, ON means Kermit\n\
+  does its own echoing.  Synonym for SET DUPLEX { FULL, HALF }."));
+
+case XYESC:
+    return(hmsga(hxyesc));              /* SET ESCAPE */
+#endif /* NOLOCAL */
+
+case XYPRTR:                            /* SET PRINTER */
+    return(hmsga(hxyprtr));
+
+#ifdef OS2
+#ifdef BPRINT
+case XYBDCP:                            /* SET BPRINTER */
+    return(hmsga(hxybprtr));
+#endif /* BPRINT */
+#endif /* OS2 */
+
+case XYEXIT:
+    return(hmsga(hxyexit));
+
+case XYFILE:
+    return(hmsga(hmxyf));
+
+case XYFLOW:
+    return(hmsga(hmxyflo));
+
+case XYHAND:
+   return(hmsga(hmxyhsh));
+
+#ifdef NETCONN
+
+case XYHOST:
+    return(hmsga(hxyhost));
+
+case XYNET:
+    return(hmsga(hxynet));
+
+#ifndef NOTCPOPTS
+#ifdef SOL_SOCKET
+case XYTCP:
+    return(hmsga(hxytcp));
+#endif /* SOL_SOCKET */
+#endif /* NOTCPOPTS */
+
+#ifdef ANYX25
+case XYX25:
+    return(hmsga(hxyx25));
+
+#ifndef IBMX25
+case XYPAD:
+    return(hmsg("Syntax: SET PAD name value\n\
+Set a PAD X.3 parameter with a desired value."));
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+#endif /* NETCONN */
+
+#ifndef NOSPL
+case XYOUTP:
+    return(hmsga(hxyout));
+#endif /* NOSPL */
+
+#ifndef NOSETKEY
+case XYKEY:                             /* SET KEY */
+    return(hmsga(hmhskey));
+#endif /* NOSETKEY */
+
+#ifndef NOCSETS
+case XYLANG:
+    return(hmsg("Syntax: SET LANGUAGE name\n\
+  Selects language-specific translation rules for text-mode file transfers.\n\
+  Used with SET FILE CHARACTER-SET and SET TRANSFER CHARACTER-SET when one\n\
+  of these is ASCII."));
+#endif /* NOCSETS */
+
+case XYLINE:
+    printf("\nSyntax: SET LINE (or SET PORT) [ switches ] [ devicename ]\n\
+  Selects a serial-port device to use for making connections.\n");
+#ifdef OS2
+#ifdef NT
+    printf("\n");
+    printf(
+"  You may access communication ports by the traditional \"DOS\" port name\n");
+    printf(
+"  (e.g. SET PORT COM1) or by the Microsoft Telephony modem name from the\n");
+    printf(
+"  Modems folder of the Control Panel (e.g. SET PORT TAPI). If one method\n");
+    printf("  doesn't work, try the other.\n\n");
+#endif /* NT */
+#else  /* OS2 */
+    printf("  Typical device name for this platform: %s.\n",ttgtpn());
+    printf("  The default device name is %s (i.e. none).\n",dftty);
+    if (!dfloc) {
+        printf(
+"  If you do not give a SET LINE command or if you give a SET LINE command\n");
+        printf(
+"  with no device name, or if you specify %s as the device name,\n",dftty);
+        printf(
+"  Kermit will be in \"remote mode\", suitable for use on the far end of a\n");
+        printf(
+"  connection, e.g. as the file-transfer partner of your desktop communication\
+\n");
+        printf(
+"  software.  If you SET LINE to a specific device other than %s,\n", dftty);
+        printf(
+"  Kermit is in \"local mode\", suitable for making a connection to another\n"
+              );
+        printf(
+"  computer.  SET LINE alone resets Kermit to remote mode.\n");
+    }
+#endif /* OS2 */
+        printf(
+"  To use a modem to dial out, first SET MODEM TYPE (e.g., to USR), then\n");
+    printf(
+#ifdef OS2
+"  SET PORT COMx (or SET PORT TAPI), SET SPEED, then give a DIAL command.\n");
+#else
+"  SET LINE xxx, then SET SPEED, then give a DIAL command.\n");
+#endif /* OS2 */
+    printf(
+#ifdef OS2
+"  For direct null-modem connections use SET MODEM TYPE NONE, SET PORT COMx,\n"
+#else
+"  For direct null-modem connections, use SET MODEM TYPE NONE, SET LINE xxx,\n"
+#endif /* OS2 */
+    );
+    printf(
+"  then SET FLOW, SET SPEED, and CONNECT.\n");
+    printf(
+"\nOptional switches:\n\
+  /CONNECT - Enter CONNECT mode automatically if SET LINE succeeds.\n");
+    printf(
+"  /SERVER  - Enter server mode automatically if SET LINE succeeds.\n");
+#ifdef VMS
+    printf(
+"  /SHARE   - Open the device in shared mode.\n");
+    printf(
+"  /NOSHARE - Open the device in exclusive mode.\n");
+#endif /* VMS */
+    printf("\n");
+    printf(
+"Also see HELP SET MODEM, HELP SET DIAL, HELP SET SPEED, HELP SET FLOW.\n");
+    return(0);
+
+#ifndef NOSPL
+case XYMACR:
+    return(hmsga(hxymacr));
+#endif /* NOSPL */
+
+#ifndef NODIAL
+case XYMODM:
+    return(hmsga(hxymodm));
+#endif /* NODIAL */
+
+case XYPARI:
+    return(hmsga(hxypari));
+
+case XYPROM:
+    return(hmsga(hmxyprm));
+
+case XYQUIE:
+    return(hmsg("Syntax: SET QUIET {ON, OFF}\n\
+  Normally OFF.  ON disables most information messages during interactive\n\
+  operation."));
+
+#ifdef CK_SPEED
+case XYQCTL:
+    return(hmsga(hmxyqctl));
+#endif /* CK_SPEED */
+
+case XYRETR:
+    return(hmsg("Syntax: SET RETRY number\n\
+  In Kermit protocol file transfers: How many times to retransmit a\n\
+  particular packet before giving up; 0 = no limit."));
+
+#ifndef NOLOCAL
+case XYSESS:
+#ifdef UNIX
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef datageneral
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef STRATUS
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef AMIGA
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef GEMDOS
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef OS2
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out NUL and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef VMS
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef OSK
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out LF, NUL and XON/XOFF characters."));
+#else
+#ifdef MAC
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out LF, NUL and XON/XOFF characters."));
+#endif /* MAC */
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* GEMDOS */
+#endif /* AMIGA */
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* OS2ORUNIX */
+
+case XYSPEE:
+#ifdef OS2
+
+    return(hmsg("Syntax: SET SPEED number\n\
+  Speed for serial-port communication device specified in most recent\n\
+  SET PORT command, in bits per second.  Type SET SPEED ? for a list of\n\
+  possible speeds."));
+#else
+    return(hmsg("Syntax: SET SPEED number\n\
+  Speed for serial-port communication device specified in most recent\n\
+  SET LINE command, in bits per second.  Type SET SPEED ? for a list of\n\
+  possible speeds.  Has no effect on job's controlling terminal."));
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+case XYRECV:
+    return(hmsga(hxyrcv));
+case XYSEND:
+    return(hmsga(hxysnd));
+case XYREPT:
+    return(hmsga(hxyrpt));
+#endif /* NOXFER */
+
+#ifndef NOSERVER
+case XYSERV:
+    return(hmsga(hsetsrv));
+#endif /* NOSERVER */
+
+#ifdef TNCODE
+case XYTEL:
+    return(hmsga(hxytel));
+
+case XYTELOP:
+    return(hmsga(hxytopt));
+#endif /* TNCODE */
+
+#ifndef NOXMIT
+case XYXMIT:
+    return(hmsga(hsetxmit));
+#endif /* NOXMIT */
+
+#ifndef NOCSETS
+case XYUNCS:
+    return(hmsg("Syntax: SET UNKNOWN-CHAR-SET action\n\
+  DISCARD (default) means reject any arriving files encoded in unknown\n\
+  character sets.  KEEP means to accept them anyway."));
+#endif /* NOCSETS */
+
+#ifdef UNIX
+case XYWILD:
+    return(hmsga(hxywild));
+#endif /* UNIX */
+
+#ifndef NOXFER
+case XYWIND:
+    return(hmsga(hxywind));
+case XYXFER:
+    return(hmsga(hxyxfer));
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+#ifdef OS2MOUSE
+case XYMOUSE:
+    return(hmsga(hxymouse));
+#endif /* OS2MOUSE */
+#endif /* NOLOCAL */
+
+case XYALRM:
+    return(hmsg("Syntax: SET ALARM [ { seconds, hh:mm:ss } ]\n\
+  Number of seconds from now, or time of day, after which IF ALARM\n\
+  will succeed.  0, or no time at all, means no alarm."));
+
+case XYPROTO:
+    return(hmsga(hxyxyz));
+
+#ifdef CK_SPEED
+case XYPREFIX:
+    return(hmsg("Syntax: SET PREFIXING { ALL, CAUTIOUS, MINIMAL }\n\
+  \
+Selects the degree of control-character prefixing.  Also see HELP SET CONTROL."
+));
+#endif /* CK_SPEED */
+
+#ifdef OS2
+case XYLOGIN:
+    return(hmsg("Syntax: SET LOGIN { USERID, PASSWORD, PROMPT } <text>\n\
+  Provides access information for use by login scripts."));
+#endif /* OS2 */
+
+#ifndef NOSPL
+case XYTMPDIR:
+    return(hmsg("Syntax: SET TEMP-DIRECTORY [ <directory-name> ]\n\
+  Overrides automatic assignment of \\v(tmpdir) variable."));
+#endif /* NOSPL */
+
+#ifdef OS2
+case XYTITLE:
+    return(hmsg("Syntax: SET TITLE <text>\n\
+  Sets window title to text instead of using current host/port name."));
+#endif /* OS2 */
+
+#ifndef NOPUSH
+#ifndef NOFRILLS
+case XYEDIT:
+    return(hmsg("Syntax: SET EDITOR pathname [ options ]\n\
+  Specifies the name of your preferred editor, plus any command-line\n\
+  options.  SHOW EDITOR displays it."));
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+
+#ifdef BROWSER
+case XYBROWSE:
+#ifdef NT
+    return(hmsg("Syntax: SET BROWSER [ pathname [ options ] ]\n\
+  Specifies the name of your preferred browser plus any command-line\n\
+  options.  SHOW BROWSER displays it.  Omit pathname and options to use\n\
+  ShellExecute."));
+#else
+    return(hmsg("Syntax: SET BROWSER [ pathname [ options ] ]\n\
+  Specifies the name of your preferred browser plus any command-line\n\
+  options.  SHOW BROWSER displays it."));
+#endif /* NT */
+#endif /* BROWSER */
+
+#ifdef CK_TAPI
+case XYTAPI:
+    return(hmsga(hxytapi));
+#endif /* CK_TAPI */
+
+#ifdef NT
+case XYWIN95:
+    return(hmsga(hxywin95));
+#endif /* NT */
+
+#ifndef NOSPL
+case XYFUNC:
+    return(hmsga(hxyfunc));
+#endif /* NOSPL */
+
+#ifdef CK_AUTHENTICATION
+case XYAUTH:
+    return(hmsga(hmxyauth));
+#else /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+case XYAUTH:
+    return(hmsga(hmxyauth));
+#endif /* CK_SSL */
+#endif /* CK_AUTHENTICATION */
+
+#ifdef BROWSER
+case XYFTP:
+    return(hmsg("Syntax: SET FTP [ pathname [ options ] ]\n\
+  Specifies the name of your ftp client, plus any command-line options.\n\
+  SHOW FTP displays it."));
+#endif /* BROWSER */
+
+case XYSLEEP:
+    return(hmsg("Syntax: SET SLEEP CANCELLATION { ON, OFF }\n\
+  Tells whether SLEEP (PAUSE) or WAIT commands can be interrupted from the\n\
+  keyboard; ON by default."));
+
+case XYCD:
+    return(hmsga(hmxycd));
+
+case XYSERIAL:
+    return(hmsg("Syntax: SET SERIAL dps\n\
+  d is data length in bits, 7 or 8; p is first letter of parity; s is stop\n\
+  bits, 1 or 2.  Examples: \"set serial 7e1\", \"set serial 8n1\"."));
+
+#ifdef HWPARITY
+case XYSTOP:
+    return(hmsg("Syntax: SET STOP-BITS { 1, 2 }\n\
+  Number of stop bits to use on SET LINE connections, normally 1."));
+#endif /* HWPARITY */
+
+#ifndef NOLOCAL
+case XYDISC:
+    return(hmsg("Syntax: SET DISCONNECT { ON, OFF }\n\
+  Whether to close and release a SET LINE device automatically upon\n\
+  disconnection; OFF = keep device open (default); ON = close and release."));
+#endif /* NOLOCAL */
+
+#ifdef STREAMING
+case XYSTREAM:
+    return(hmsg("Syntax: SET STREAMING { ON, OFF, AUTO }\n\
+  Tells Kermit whether streaming protocol can be used during Kermit file\n\
+  transfers.  Default is AUTO, meaning use it if connection is reliable."));
+#endif /* STREAMING */
+
+case XYRELY:
+    return(hmsg("Syntax: SET RELIABLE { ON, OFF, AUTO }\n\
+  Tells Kermit whether its connection is reliable.  Default is AUTO,\n\
+  meaning Kermit should figure it out for itself."));
+
+case XYCLEAR:
+    return(hmsg("Syntax: SET CLEAR-CHANNEL { ON, OFF, AUTO }\n\
+  Tells Kermit whether its connection is transparent to all 8-bit bytes.\n\
+  Default is AUTO, meaning Kermit figures it out from the connection type.\n\
+  When both sender and receiver agree channel is clear, SET PREFIXING NONE\n\
+  is used automatically."));
+
+#ifdef TLOG
+case XYTLOG:
+    return(hmsg("Syntax: SET TRANSACTION-LOG { BRIEF, FTP, VERBOSE }\n\
+  Selects the transaction-log format; BRIEF and FTP have one line per file;\n\
+  FTP is compatible with FTP log.  VERBOSE (the default) has more info."));
+#endif /* TLOG */
+
+case XYOPTS:
+    return(hmsg("Syntax: SET OPTIONS command [ switches... ]\n\
+  For use with commands that have switches; sets the default switches for\n\
+  the given command.  Type SET OPTIONS ? for a list of amenable commands."));
+
+#ifndef NOSPL
+case XYTIMER:
+    return(hmsga(hmxytimer));
+#endif /* NOSPL */
+
+#ifdef CKROOT
+  case XYROOT:
+    return(hmsga(hmxxchroot));
+#endif /* XYROOT */
+
+#ifdef ANYSSH
+  case XYSSH:
+    return(hmsga(hmxyssh));
+#endif /* ANYCMD */
+
+#ifdef LOCUS
+  case XYLOCUS:
+    return(hmsga(hmxylocus));
+#endif /* LOCUS */
+
+#ifdef OS2
+#ifdef KUI
+  case XYGUI:
+    return(hmsga(hmxygui));
+#endif /* KUI */
+#endif /* OS2 */
+
+  case XYMATCH:
+    return(hmsga(hmxymatch));
+
+default:
+    printf("Not available - \"%s\"\n",cmdbuf);
+    return(0);
+    }
+}
+
+#ifndef NOSPL
+/*  D O H F U N C  --  Give help for a function  */
+
+int
+dohfunc(xx) int xx; {
+    /* int x; */
+    if (xx == -3) {
+        printf("\n Type SHOW FUNCTIONS to see a list of available functions.\n"
+               );
+        printf(
+        " Type HELP FUNCTION <name> for help on a particular function.\n");
+        printf(
+        " For function settings use HELP SET FUNCTION and SHOW SCRIPTS.\n\n");
+        return(0);
+    }
+    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)\n\
+  s1 = string to look for.\n\
+  s2 = string to look in.\n\
+  n1 = optional 1-based starting position, 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_SEARCH:                   /* Search for pattern */
+      case FN_RSEARCH:                  /* Search for pattern from right */
+        printf("\\f%ssearch(s1,s2,n1)\n\
+  s1 = pattern to look for.\n\
+  s2 = string to look in.\n\
+  n1 = optional 1-based offset, 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("  See HELP WILDCARDS for info about patterns.\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.\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])\n\
+  s1 = original string.\n\
+  s2 = match string.\n\
+  s3 = replacement string.\n\
+  n1 = occurrence.\n");
+        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)\n\
+  s1 = string to look in.\n\
+  c1 = character to look for, default = \".\".\n");
+        printf("Returns string:\n\
+  The part of s1 after the leftmost 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) - 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 */
+        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");
+        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");
+        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");
+        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\
+  pattern = String\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_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");
+        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 translated to 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");
+        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,c1)\n\
+  s1 = string of the form \"name=value\"\n\
+  c1 = separator character (default separator is \"=\")\n");
+        printf("    Assigns the value, if any, to the named macro.\n");
+        printf("    If s1 contains no separator, nothing happens.\n");
+        printf(
+"    If s1 contains a separator but no value, the macro is undefined.\n");
+        printf("Returns:\n");
+        printf("  0 on failure\n");
+        printf("  1 on success\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 */
+
+      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 <name> 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("\\Kdecfselect    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_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_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("\\Ktnayt         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("\\Klogdebug      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("\\Kdshome        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
+dohrmt(xx) int xx; {
+    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 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 */
+
+default:
+    if ((x = cmcfm()) < 0) return(x);
+    printf("?Sorry, no help available - \"%s\"\n",cmdbuf);
+    return(-9);
+    }
+}
+#endif /* NOXFER */
+#endif /* NOHELP */
+#endif /* NOICP */
diff --git a/ckermit-8.0.211/ckuus3.c b/ckermit-8.0.211/ckuus3.c
new file mode 100644
index 0000000..8d2f8b6
--- /dev/null
+++ b/ckermit-8.0.211/ckuus3.c
@@ -0,0 +1,13310 @@
+#ifdef SSHTEST
+#define SSHBUILTIN
+#endif /* SSHTEST */
+
+#include "ckcsym.h"                     /* Symbol definitions */
+
+/*  C K U U S 3 --  "User Interface" for C-Kermit, part 3  */
+
+/*
+  Authors:
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    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.
+*/
+
+/*  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 <os2.h>
+#ifdef COMMENT                          /* Would you believe */
+#undef COMMENT                          /* <os2.h> 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;
+#ifdef NT
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"                     /* Microsoft TAPI */
+#endif /* NT */
+#endif /* OS2 */
+
+#ifndef OS2
+extern char * exedir;
+#endif /* OS2 */
+
+#ifdef CK_RECALL
+extern int cm_retry;
+#endif /* CK_RECALL */
+
+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 */
+
+/* Variables */
+
+int cmd_quoting = 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;
+
+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, 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 */
+#endif /* NOLOCAL */
+
+char * tempdir = NULL;
+
+#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, CM_INV,                     /* Same as B */
+    "blank-free-2", 4, 0                /* B = 12-bit checksum, no blanks */
+};
+
+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 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
+
+struct keytab dbgtab[] = {
+    "linelength", DEB_LEN, 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 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_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,
+    "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 */
+
+#ifndef NOPUSH
+extern int nopush;
+#ifdef UNIX
+struct keytab wildtab[] = {             /* SET WILDCARD-EXPANSION */
+    "kermit",  0, 0,
+    "shell",   1, 0
+};
+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,
+#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 */
+    "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) */
+
+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 */
+    "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 */
+    "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 */
+
+#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 /* NOXMIT */
+
+"", 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
+parsdir(cx) int cx; {
+    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,(char *)GetAppData(0));
+            makestr(&appdata1,(char *)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 <CR> */
+                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
+getyesno(msg, flags) char * msg; int flags; {
+#ifdef CK_RECALL
+    extern int on_recall;               /* around Password prompting */
+#endif /* CK_RECALL */
+    int y, z;
+
+#ifndef NOLOCAL
+#ifdef OS2
+    extern int vmode, 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_saveas_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 */ {
+    int rc, len;
+    char * text=NULL;
+
+    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);
+        ShowWindowAsync(hwndConsole,SW_SHOWNORMAL);
+        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));
+        ShowWindowAsync(hwndConsole,SW_SHOWNORMAL);
+        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 int vmode;
+    extern int startflags;
+    extern int win95_popup;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+    int rc; 
+
+    if (buflen < 1 || !buf)
+      return(0);
+#ifdef KUI
+    if ( gui_dialog ) {
+        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 int vmode;
+    extern int startflags;
+    extern int win95_popup;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+    int i, rc;
+
+    if (n < 1 || !field)
+      return(0);
+#ifdef KUI
+    if ( gui_dialog ) {
+        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
+    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_saveas_dialog(preface,fprompt,fc,dflt,result,rlength);
+        return rc;
+    }
+#endif /* KUI */
+
+#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
+};
+
+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
+
+/* 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|SXF_TWO, /* Comparisons */
+    ">",       SX_AGT, SXF_PRE|SXF_TWO,
+    "<=",      SX_ALE, SXF_PRE|SXF_TWO,
+    "=",       SX_AEQ, SXF_PRE|SXF_TWO,
+    ">=",      SX_AGE, SXF_PRE|SXF_TWO,
+    "!=",      SX_NEQ, SXF_PRE|SXF_TWO,
+
+    "++",      SX_INC, SXF_ONE|SXF_TWO, /* Increment */
+    "--",      SX_DEC, SXF_ONE|SXF_TWO, /* Decrement */
+
+    "**",      SX_POW, SXF_TWO,         /* Common synonyms */
+    "==",      SX_AEQ, SXF_PRE|SXF_TWO,
+    "!",       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",  SX_STR, 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_FLO,
+    "ceiling", SX_CEI, SXF_ONE|SXF_FLO,
+    "floor",   SX_FLR, SXF_ONE|SXF_FLO,
+    "float",   SX_FLO, SXF_ONE|SXF_FLO,
+
+#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 */
+
+#define SXMLEN 64                       /* Macro arg list initial length */
+#include <math.h>                       /* Floating-point functions */
+
+_PROTOTYP( char * fpformat, (CKFLOAT, int, int) );
+
+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(" last sexpression:        %s\n",lastsexp ? lastsexp : "(none)");
+    printf(" last value:              %s\n",sexpval ? sexpval : "(none)");
+    printf("\n");
+}
+
+
+static char *
+sexpdebug(s) char * s; {
+    /* 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) */
+
+char *
+dosexp(s) char *s; {                    /* s = S-Expression */
+    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 i, j, k, n = 0, x = 0, kw, kwflags, mx = 0;
+    int result = 0, not = 0, truncate = 0, builtin = 0;
+    int fpflag = 0, quit = 0, macro = 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 */
+
+    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"),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) */
+
+    p[0] = NULL;                        /* (We don't use element 0) */
+    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);
+        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;
+        }
+        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 */
+            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') {
+            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);
+		debug(F111,"XXX",p[1],x);
+                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 {                /* Not found in macro table */
+                    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++;
+            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? */
+                pflag = 1;
+                presult = 1;
+            }
+            if (kwflags & SXF_FLO)      /* Operator requires floating point */
+              fpflag++;                 /* Force it */
+        }
+        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 = atoi(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 = atoi(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;
+                    }
+                    if (result != fpresult) fpflag++;
+                    s2 = fpflag ? fpformat(fpresult,0,0) : ckitoa(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 = atoi(s2);
+            }
+            goto xdosexp;
+        } else if (x == SX_IFC) {               /* Conditional expression */
+            int true = 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 = atoi(s2);
+                if (xxfloat(s2,0) == 2) {
+                    fpflag++;
+                    fpresult = (CKFLOAT)result;
+                    fpj = floatval;
+                } else {
+                    fpj = atof(s2);
+                }
+                true = ((fpj != 0.0) ? 1 : 0);
+            }
+            if (!true && n < 4) {
+                s2 = NULL;
+            } else {
+                s2 = dosexp(true ? p[3] : p[4]);
+                if (sexprc) goto xdosexp;
+                j = s2 ? atoi(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) {
+#ifndef COMMENT
+            int xx;
+            xx = strlen(p[2]);
+            p[3] = (char *)malloc(xx+4);
+            s2 = p[3];
+            ckmakmsg(p[3],xx+4,"'(",p[2],")",NULL);
+            n++;
+#else
+            s2 = p[2];
+#endif /* COMMENT */
+            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') {            /* Is it quoted? */
+            s2 = dosexp(p[i+1]);        /* No, evaluate it */
+            if (sexprc) goto xdosexp;
+            if (!s2) s2 = "";
+            if (!macro && x == SX_EVA)
+              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);
+        }
+#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 = atoi(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 (!(kwflags & SXF_ONE))   /* Command with 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;
+            if (result != fpresult)
+              fpflag++;
+            break;
+
+          case SX_SUB:                  /* - */
+            result -= j;
+            fpresult -= fpj;
+            if (result != fpresult)
+              fpflag++;
+            break;
+
+          case SX_MUL:                  /* * */
+            result *= j;
+            fpresult *= fpj;
+            if (result != fpresult)
+              fpflag++;
+            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:                  /* / */
+            result /= j;
+            fpresult /= fpj;
+            if (result != fpresult)
+              fpflag++;
+            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 {
+                int 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;
+            }
+            if (result != fpresult)
+              fpflag++;
+            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_ROU:                  /* Round */
+            if (fpj > 0.0)
+              fpj += 0.5;
+            else if (fpj < 0.0)
+              fpj -= 0.5;
+            fpresult = fpj;
+            fpflag = 1;
+            truncate = 1;
+            break;
+
+          case SX_ABS:                  /* Absolute value */
+            result = (j < 0) ? 0 - j : j;
+            fpresult = (fpj < 0.0) ? 0.0 - fpj : fpj;
+            if (result != fpresult)
+              fpflag++;
+            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) {                /* 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 = ckitoa(result);
+    }
+
+/* Common exit point.  Always come here to exit. */
+
+  xdosexp:
+
+    if (!s2) s2 = "";
+    if (!sexprc && s2) {                /* Have a result */
+        char * sx;
+        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;
+                    }
+                }
+            }
+        }
+    }
+    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);
+    return(sxresult[sexpdep--]);
+}
+#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);
+#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) {
+        int x = locus;
+#ifdef NEWFTP
+        extern int ftpisconnected();
+	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);
+        strncat(cxlogbuf,"E=",CXLOGBUFL); /* Append to log record */
+        strncat(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
+dologshow(fc) int fc; {                 /* SHOW (current) CONNECTION */
+    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 '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;
+    int n, m;
+
+    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)
+      s = "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 */
+    }
+    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 ",
+                uu,
+                ckgetpid(),
+                s,
+                ttname,
+                myhost
+                );
+    } else
+      ckstrncpy(cxlogbuf,"LOGNET BUFFER OVERFLOW",CXLOGBUFL);
+    debug(F110,"dolognet cxlogbuf",cxlogbuf,0);
+}
+#endif /* NETCONN */
+#endif /* CKLOGDIAL */
+
+#ifndef NODIAL
+/*
+  Parse a DIAL-related string, stripping enclosing braces, if any.
+*/
+static int
+dialstr(p,msg) char **p; char *msg; {
+    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
+initmdm(x) int x; {
+    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 */
+setdial(y) int y; {
+    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 i = 0, j = 9999, 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
+#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 <Return> */
+            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 <scancode> <value> 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));
+
+#define XPCMDLEN 71
+
+_PROTOTYP(static int protofield, (char *, char *, char *));
+_PROTOTYP(static int setproto, (void));
+
+static int
+protofield(current, help, px) char * current, * help, * px; {
+
+    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;
+
+#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) {
+            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);
+}
+
+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
+setprinter(xx) int xx; {
+    int x, y;
+    char * s;
+    char * defname = NULL;
+#ifdef OS2
+    extern int prncs;
+#endif /* OS2 */
+
+#ifdef BPRINT
+    char portbuf[64];
+    long portspeed = 0L;
+    int portparity = 0;
+    int portflow = 0;
+#endif /* BPRINT */
+
+#ifdef PRINTSWI
+    int c, i, n, wild, confirmed = 0;   /* Workers */
+    int getval = 0;                     /* Whether to get switch value */
+    struct stringint {                  /* Temporary array for switch values */
+        char * sval;
+        int ival;
+    } pv[PRN_MAX+1];
+    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 */
+    }
+    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 = x;
+              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 */
+#endif /* SSHBUILTIN */
+
+static struct keytab sshtab[] = {       /* SET SSH command table */
+#ifdef SSHBUILTIN
+    { "agent-forwarding",        SSH_AFW,  0 },
+    { "check-host-ip",           SSH_CHI,  0 },
+    { "compression",             SSH_CMP,  0 },
+    { "dynamic-forwarding",      SSH_DYF,  0 },
+    { "gateway-ports",           SSH_GWP,  0 },
+    { "gssapi",                  SSH_GSS,  0 },
+    { "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 },
+    { "k5",                      SSH_K5, CM_INV },
+    { "kerberos4",               SSH_K4,   0 },
+    { "kerberos5",               SSH_K5,   0 },
+    { "krb4",                    SSH_K4, CM_INV },
+    { "krb5",                    SSH_K5, CM_INV },
+    { "privileged-port",         SSH_PRP,  0 },
+    { "quiet",                   SSH_SHH,  0 },
+    { "strict-host-key-check",   SSH_SHK,  0 },
+    { "use-openssh-config",      SSH_CFG,  0 },
+    { "v1",                      SSH_V1,   0 },
+    { "v2",                      SSH_V2,   0 },
+    { "verbose",                 SSH_VRB,  0 },
+    { "version",                 SSH_VER,  0 },
+    { "x11-forwarding",          SSH_XFW,  0 },
+    { "xauth-location",          SSH_XAL,  0 },
+#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 SSHA_CRS   1
+#define SSHA_DSA   2
+#define SSHA_GSS   3
+#define SSHA_HOS   4
+#define SSHA_KBD   5
+#define SSHA_K4    6
+#define SSHA_K5    7
+#define SSHA_PSW   8
+#define SSHA_PK    9
+#define SSHA_SKE  10
+#define SSHA_TIS  11
+#define SSHA_EXT  12
+#define SSHA_SRP  13
+
+static struct keytab ssh2aut[] = {      /* SET SSH V2 AUTH command table */
+    { "external-keyx",      SSHA_EXT, 0 },
+    { "gssapi",             SSHA_GSS, 0 },
+    { "hostbased",          SSHA_HOS, 0 },
+    { "keyboard-interactive",  SSHA_KBD, 0 },
+    { "password",           SSHA_PSW, 0 },
+    { "publickey",          SSHA_PK,  0 },
+    { "srp-gex-sha1",       SSHA_SRP, 0 },
+    { "", 0, 0 }
+};
+static int nssh2aut = (sizeof(ssh2aut) / sizeof(struct keytab)) - 1;
+
+#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
+
+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 },
+    { "macs",                    SSH2_MAC, 0 },
+    { "user-known-hosts-file",   SSH2_UNH, 0 },
+    { "", 0, 0 }
+};
+static int nsshv2tab = (sizeof(sshv2tab) / sizeof(struct keytab)) - 1;
+
+#define SSHC_3DES 1                     /* 3DES */
+#define SSHC_3CBC 2                     /* 3DES-CBC */
+#define SSHC_A128 3                     /* AES128-CBC */
+#define SSHC_A192 4                     /* AES192-CBC */
+#define SSHC_A256 5                     /* AES256-CBC */
+#define SSHC_ARC4 6                     /* ARCFOUR */
+#define SSHC_FISH 7                     /* BLOWFISH */
+#define SSHC_BCBC 9                     /* BLOWFISH-CBC */
+#define SSHC_C128 8                     /* CAST128-CBC */
+#define SSHC_1DES 10                    /* DES */
+
+static struct keytab ssh1ciphers[] = {
+    { "3des",         SSHC_3DES, 0 },
+    { "blowfish",     SSHC_FISH, 0 },
+    { "des",          SSHC_1DES, 0 },
+    { "", 0, 0 }
+};
+static int nssh1ciphers = (sizeof(ssh1ciphers) / sizeof(struct keytab)) - 1;
+
+static struct keytab ssh2ciphers[] = {  /* SET SSH V2 CIPHERS command table */
+    { "3des-cbc",        SSHC_3DES, 0 },
+    { "aes128-cbc",      SSHC_A128, 0 },
+    { "aes192-cbc",      SSHC_A192, 0 },
+    { "aes256-cbc",      SSHC_A256, 0 },
+    { "arcfour",         SSHC_ARC4, 0 },
+    { "blowfish-cbc",    SSHC_FISH, 0 },
+    { "cast128-cbc",     SSHC_C128, 0 },
+    { "rijndael128-cbc", SSHC_A128, 0 },
+    { "rijndael192-cbc", SSHC_A192, 0 },
+    { "rijndael256-cbc", SSHC_A256, 0 },
+    { "", 0, 0 }
+};
+static int nssh2ciphers = (sizeof(ssh2ciphers) / sizeof(struct keytab)) - 1;
+
+#define SSHM_SHA        1               /* HMAC-SHA1 */
+#define SSHM_SHA_96     2               /* HMAC-SHA1-96 */
+#define SSHM_MD5        3               /* HMAC-MD5 */
+#define SSHM_MD5_96     4               /* HMAC-MD5-96 */
+#define SSHM_RIPE       5               /* HMAC-RIPEMD160 */
+
+static struct keytab ssh2macs[] = {     /* SET SSH V2 MACS command table */
+    { "hmac-md5",       SSHM_MD5,    0 },
+    { "hmac-md5-96",    SSHM_MD5_96, 0 },
+    { "hmac-ripemd160", SSHM_RIPE,   0 },
+    { "hmac-sha1",      SSHM_SHA,    0 },
+    { "hmac-sha1-96",   SSHM_SHA_96, 0 },
+    { "", 0, 0 }
+};
+static int nssh2macs = (sizeof(ssh2macs) / sizeof(struct keytab)) - 1;
+
+static struct keytab tgtpass[] = {
+    { "tgt-passing", 1, 0, },
+    { "", 0, 0 }
+};
+static int ntgtpass = (sizeof(tgtpass) / sizeof(struct keytab)) - 1;
+
+static struct keytab gssapitab[] = {
+    { "delegate-credentials", 1, 0, },
+    { "key-exchange",         2, CM_INV, },
+    { "", 0, 0 }
+};
+static int ngssapitab = (sizeof(gssapitab) / sizeof(struct keytab)) - 1;
+
+#define HKA_RSA 1
+#define HKA_DSS 2
+
+static struct keytab hkatab[] = {
+    { "ssh-dss", HKA_DSS, 0, },
+    { "ssh-rsa", HKA_RSA, 0, },
+    { "", 0, 0 }
+};
+static int nhkatab = (sizeof(hkatab) / sizeof(struct keytab)) - 1;
+
+int                                     /* SET SSH variables */
+  ssh_afw = 0,                          /* agent forwarding */
+  ssh_xfw = 0,                          /* x11 forwarding   */
+  ssh_prp = SET_OFF,                    /* privileged ports */
+  ssh_cmp = 1,                          /* compression */
+  ssh_shh = 0,                          /* quiet       */
+  ssh_ver = 0,                          /* protocol version (auto,1,2) */
+  ssh_vrb = 2,                          /* Report errors */
+  ssh_chkip = 0,                        /* SSH Check Host IP flag */
+  ssh_gwp = 0,                          /* gateway ports */
+  ssh_dyf = 0,                          /* dynamic forwarding */
+  ssh_gsd = 0,                          /* gssapi delegate credentials */
+  ssh_k4tgt = 0,                        /* k4 tgt passing */
+  ssh_k5tgt = 0,                        /* k5 tgt passing */
+  ssh_shk = 2,                          /* Strict host key (no, yes, ask) */
+  ssh2_ark = 1,                         /* Auto re-key */
+  ssh_cas = 0,                          /* command as subsys */
+  ssh_cfg = 0,                          /* use OpenSSH config? */
+  ssh_gkx = 1,                          /* gssapi key exchange */
+  ssh_k5_is_k4 = 1,                     /* some SSH v1 use same codes */
+  ssh_hbt = 0,                          /* heartbeat (seconds) */
+  ssh_dummy = 0;                        /* bottom of list */
+
+char                                    /* The following are to be malloc'd */
+  * ssh1_cif = NULL,                    /* v1 cipher */
+  * ssh2_cif = NULL,                    /* v2 cipher list */
+  * ssh2_mac = NULL,                    /* v2 mac list */
+  * ssh2_auth = NULL,                   /* v2 authentication list */
+  * ssh_hst = NULL,                     /* hostname */
+  * ssh_prt = NULL,                     /* port/service */
+  * ssh_cmd = NULL,                     /* command to execute */
+  * ssh_xal = NULL,                     /* xauth-location */
+  * ssh1_gnh = NULL,                    /* v1 global known hosts file */
+  * ssh1_unh = NULL,                    /* v1 user known hosts file */
+  * ssh2_gnh = NULL,                    /* v2 global known hosts file */
+  * ssh2_unh = NULL,                    /* v2 user known hosts file */
+  * ssh2_hka = NULL,                    /* Host Key Algorithms */
+  * xxx_dummy = NULL;
+
+char * ssh_idf[32] = {                  /* 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
+};
+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;
+
+extern int    ssh_pf_lcl_n,
+              ssh_pf_rmt_n;
+extern struct ssh_pf ssh_pf_lcl[32];    /* Port forwarding structs */
+extern struct ssh_pf ssh_pf_rmt[32];    /* (declared in ckuusr.c) */
+#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;                       /* ADD askmore()! */
+
+    printf("\nSSH is built in:\n\n");
+
+    printf(" ssh host:                        %s\n",showstring(ssh_hst));
+    printf(" ssh port:                        %s\n",showstring(ssh_prt));
+    printf(" ssh command:                     %s\n",showstring(ssh_cmd));
+    printf(" ssh agent-forwarding:            %s\n",showoff(ssh_afw));
+    printf(" ssh check-host-ip:               %s\n",showoff(ssh_chkip));
+    printf(" ssh compression:                 %s\n",showoff(ssh_cmp));
+    printf(" ssh dynamic-forwarding:          %s\n",showoff(ssh_dyf));
+    if (ssh_pf_lcl[0].p1 && ssh_pf_lcl[0].host && ssh_pf_lcl[0].p2) {
+      printf(" ssh forward-local-port:          %d %s %d\n",
+             ssh_pf_lcl[0].p1, ssh_pf_lcl[0].host, ssh_pf_lcl[0].p2);
+      for ( n=1;n<ssh_pf_lcl_n;n++ )
+        printf("                       :          %d %s %d\n",
+               ssh_pf_lcl[n].p1, ssh_pf_lcl[n].host, ssh_pf_lcl[n].p2);
+    } else
+      printf(" ssh forward-local-port:         (none)\n");
+    if (ssh_pf_rmt[0].p1 && ssh_pf_rmt[0].host && ssh_pf_rmt[0].p2) {
+      printf(" ssh forward-remote-port:         %d %s %d\n",
+             ssh_pf_rmt[0].p1, ssh_pf_rmt[0].host, ssh_pf_rmt[0].p2);
+      for ( n=1;n<ssh_pf_rmt_n;n++ )
+        printf("                        :         %d %s %d\n",
+               ssh_pf_rmt[n].p1, ssh_pf_rmt[n].host, ssh_pf_rmt[n].p2);
+    } else
+      printf(" ssh forward-remote-port:        (none)\n");
+    printf(" ssh gateway-ports:               %s\n",showoff(ssh_gwp));
+    printf(" ssh gssapi delegate-credentials: %s\n",showoff(ssh_gsd));
+    printf(" ssh gssapi key-exchange        : %s\n",showoff(ssh_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_hbt);
+    printf(" ssh k4 tgt-passing:              %s\n",showoff(ssh_k4tgt));
+    printf(" ssh k5 tgt-passing:              %s\n",showoff(ssh_k5tgt));
+
+    printf(" ssh privileged-port:             %s\n",showooa(ssh_prp));
+    printf(" ssh quiet:                       %s\n",showoff(ssh_shh));
+    printf(" ssh strict-host-key-check:       %d\n",ssh_shk);
+    printf(" ssh use-openssh-config:          %s\n",showoff(ssh_cfg));
+    printf(" ssh verbose:                     %d\n",ssh_vrb);
+    printf(" ssh version:                     %s\n",
+           ssh_ver ? ckitoa(ssh_ver) : "automatic"
+           );
+    printf(" ssh x11-forwarding:              %s\n",showooa(ssh_xfw));
+    printf(" ssh xauth-location:              %s\n",showstring(ssh_xal));
+    printf("\n");
+    printf(" ssh v1 cipher:                   %s\n",showstring(ssh1_cif));
+    printf(" ssh v1 global-known-hosts-file:  %s\n",showstring(ssh1_gnh));
+    printf(" ssh v1 user-known-hosts-file:    %s\n",showstring(ssh1_unh));
+    printf("\n");
+    printf(" ssh v2 authentication:           %s\n",showstring(ssh2_auth));
+    printf(" ssh v2 auto-rekey:               %s\n",showoff(ssh2_ark));
+    printf(" ssh v2 ciphers:                  %s\n",showstring(ssh2_cif));
+    printf(" ssh v2 command-as-subsystem:     %s\n",showoff(ssh_cas));
+    printf(" ssh v2 global-known-hosts-file:  %s\n",showstring(ssh2_gnh));
+    printf(" ssh v2 hostkey-algorithms:       %s\n",showstring(ssh2_hka));
+    printf(" ssh v2 mac:                      %s\n",showstring(ssh2_mac));
+    printf(" ssh v2 user-known-hosts-file:    %s\n",showstring(ssh2_unh));
+#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");
+}
+
+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;
+
+    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 */
+        return(success = seton(&ssh_afw));
+
+      case SSH_CHI:                     /* Check Host IP */
+        return(success = seton(&ssh_chkip));
+        break;
+
+      case SSH_CMP:                     /* Compression */
+        return(success = seton(&ssh_cmp));
+
+      case SSH_DYF:                     /* Dynamic Forwarding */
+        return(success = seton(&ssh_dyf));
+
+      case SSH_GWP:                     /* Gateway ports */
+        return(success = seton(&ssh_gwp));
+
+      case SSH_GSS:                     /* GSSAPI */
+        if ((y = cmkey(gssapitab,ngssapitab,"","", xxstring)) < 0)
+          return(y);
+        switch (y) {
+          case 1:                       /* Delegate credentials */
+            return(success = seton(&ssh_gsd));
+          case 2:                       /* key-exchange */
+            return(success = seton(&ssh_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 ((y = cmkey(tgtpass,1,"","tgt-passing", xxstring)) < 0)
+          return(y);
+        switch (y) {
+          case 1:
+            return(success = (cx == SSH_K4) ?
+                   seton(&ssh_k4tgt) : seton(&ssh_k5tgt));
+        }
+        if ((x = cmcfm()) < 0)
+          return(x);
+        return(success = 0);
+
+      case SSH_PRP:                     /* Privd port */
+        return(success = seton(&ssh_prp));
+
+      case SSH_SHH:                     /* Quiet */
+        return(success = seton(&ssh_shh));
+
+      case SSH_SHK:                     /* Strict Host Key Check */
+        if ((y = cmkey(ooktab,3,"","", xxstring)) < 0)
+          return(y);
+        if ((x = cmcfm()) < 0)
+          return(x);
+        ssh_shk = y;
+        return(success = 1);
+
+      case SSH_HBT:
+	x = cmnum("Heartbeat interval, seconds","0",10,&z,xxstring);
+	if (x < 0) return(x);
+	if ((x = cmcfm()) < 0) return(x);
+	ssh_hbt = z;
+	return(success = 1);
+
+      case SSH_V1:                      /* SSH V1 */
+        if ((y = cmkey(sshv1tab,nsshv1tab,"","", xxstring)) < 0)
+          return(y);
+        switch (y) {
+          case SSH1_K54:
+            return(success = seton(&ssh_k5_is_k4));
+          case SSH1_CIF:                /* Not a list */
+            if ((y = cmkey(ssh1ciphers,nssh1ciphers,"","", xxstring)) < 0)
+              if (y != -3)
+                return(y);
+            if ((x = cmcfm()) < 0) return(x);
+            if (y == -3) {
+                makestr(&ssh1_cif,NULL);
+            } else {
+                for (x = 0; x < nssh1ciphers; x++)
+                  if (ssh1ciphers[x].kwval == y)
+                    break;
+                makestr(&ssh1_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: makestr(&ssh1_gnh,s); break;
+              case SSH1_UNH: makestr(&ssh1_unh,s); break;
+            }
+            return(1);
+        }
+
+      case SSH_V2:                      /* SSH V2 */
+        if ((y = cmkey(sshv2tab,nsshv2tab,"","", xxstring)) < 0)
+          return(y);
+        switch (y) {
+          case SSH2_ARK:
+            return(success = seton(&ssh2_ark));
+        case SSH2_AUT: {                        /* Authentication */
+#define TMPCNT 12
+            int i, j, tmp[TMPCNT];
+            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 (ssh2_auth) {
+                free(ssh2_auth);
+                ssh2_auth = NULL;
+            }
+            if (i > 0) {
+                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);
+                }
+            }
+            return(success = 1);
+#undef TMPCNT
+          }
+        case SSH2_CIF: {
+#define TMPCNT 12
+            int i, j, tmp[TMPCNT];
+            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 (ssh2_cif) {
+                free(ssh2_cif);
+                ssh2_cif = NULL;
+            }
+            if (i > 0) {
+                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);
+                }
+            }
+            return(success = 1);
+#undef TMPCNT
+        }
+        case SSH2_MAC: {
+#define TMPCNT 12
+            int i, j, tmp[TMPCNT];
+            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 (ssh2_mac) {
+                free(ssh2_mac);
+                ssh2_mac = NULL;
+            }
+            if (i > 0) {
+                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);
+                }
+            }
+            return(success = 1);
+#undef TMPCNT
+          }
+          case SSH2_HKA: {
+#define TMPCNT 12
+            int i, j, tmp[TMPCNT];
+            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 (ssh2_hka) {
+                free(ssh2_hka);
+                ssh2_hka = NULL;
+            }
+            if (i > 0) {
+                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);
+                }
+            }
+            return(success = 1);
+#undef TMPCNT
+          }
+          case SSH2_GNH:
+          case SSH2_UNH:
+            if ((x = cmifi("Filename","",&s,&z,xxstring)) < 0) {
+                if (x != -3)
+                  return(y);
+            } 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: makestr(&ssh2_gnh,s); break;
+              case SSH2_UNH: makestr(&ssh2_unh,s); break;
+              default: return(success = 0);
+            }
+            return(success = 1);
+        }
+
+      case SSH_VRB:                     /* Verbosity level */
+        y = cmnum("SSH verbosity level, 0-7","2",10,&x,xxstring);
+        return(setnum(&ssh_vrb,x,y,7));
+
+      case SSH_VER:                     /* Version */
+        if ((y = cmkey(sshver,3,"","auto", xxstring)) < 0)
+          return(y);
+        if ((x = cmcfm()) < 0)
+          return(x);
+        ssh_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;
+        return(success = 1);
+      }
+      case SSH_XFW:                     /* X11-forwarding */
+        success = seton(&ssh_xfw);
+#ifndef SSHTEST
+        if (success)
+          sl_ssh_xfw_saved = 0;
+#endif /* SSHTEST */
+        return(success);
+
+      case SSH_XAL:                     /* SSH Xauth Location */
+        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);
+        makestr(&ssh_xal,s);
+        return(success = 1);
+
+      case SSH_CFG:                     /* Use OpenSSH Config */
+        return(success = seton(&ssh_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];
+
+#define GUI_RGB  1
+#define GUI_WIN  2
+#define GUI_FON  3
+#define GUI_DIA  4
+#define GUI_TLB  5
+#define GUI_MNB  6
+
+#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[] = {
+    { "dialogs",     GUI_DIA,  0 },
+    { "font",        GUI_FON,  0 },
+    { "menubar",     GUI_MNB,  0 },
+    { "rgbcolor",    GUI_RGB,  0 },
+    { "toolbar",     GUI_TLB,  0 },
+    { "window",      GUI_WIN,  0 },
+    { "", 0, 0}
+};
+static int nguitab = (sizeof(guitab) / 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 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, y, 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, (long)tt_font, (long)tt_font_size);
+    return(success = 1);
+}
+
+VOID
+setguidialog(x) int x;
+{
+    extern int gui_dialog;
+    gui_dialog = x;
+    KuiSetProperty(KUI_GUI_DIALOGS, (long)x, 0L);
+}
+
+VOID
+setguimenubar(x) int x;
+{
+    KuiSetProperty(KUI_GUI_MENUBAR, (long)x, 0L);
+}
+
+VOID
+setguitoolbar(x) int x;
+{
+    KuiSetProperty(KUI_GUI_TOOLBAR, (long)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:
+        rc = seton(&x);
+        if (rc >= 0)
+          setguitoolbar(x);
+        return(rc);
+      case GUI_MNB:
+        rc = seton(&x);
+        if (rc >= 0)
+          setguimenubar(x);
+        return(rc);
+      default:
+        return(-2);
+    }
+}
+#endif /* KUI */
+
+VOID
+setexitwarn(x) int x; 
+{
+    xitwarn = x;
+#ifdef KUI
+    KuiSetProperty(KUI_EXIT_WARNING, (long)x, 0L);
+#endif /* KUI */
+}
+
+#ifndef NOLOCAL
+VOID
+setdebses(x) int x; {
+#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
+doprm(xx,rmsflg) int xx, rmsflg; {
+    int i = 0, x = 0, y = 0, z = 0;
+    long zz = 0L;
+    char *s = NULL, *p = NULL;
+#ifdef OS2
+    char portbuf[64];
+    long portspeed = 0L;
+    int portparity = 0;
+    int portflow = 0;
+#endif /* OS2 */
+
+#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
+      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 SSHBUILTIN
+              if (netcmd[z].kwval == NET_SSH &&
+                   !ck_ssleay_is_installed())
+                netcmd[z].flgs =  CM_INV;
+#endif /* SSHBUILTIN */
+#ifdef DECNET
+              else 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 (tcp_avail)                /* Default network type */
+            ckstrncpy(tmpbuf,"tcp/ip",TMPBUFSIZ);
+#ifdef SSHBUILTIN
+          else if ( ck_ssleay_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 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 SSHBUILTIN
+          } else if (z == NET_SSH && !ck_ssleay_is_installed()) {
+            printf("\n?Sorry, SSH is not available on this system.\n") ;
+            return(-9);
+#endif /* SSHBUILTIN */
+#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" */
+              } 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";
+              }
+              if ((y = cmtxt((z == NET_PIPE) ? "pipe name" :
+                             "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);
+          }
+      }
+
+#ifndef NOTCPOPTS
+#ifdef TCPSOCKET
+      case XYTCP: {
+        extern int ttyfd;
+
+        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_sock != -1)
+              success = keepalive(ssh_sock,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_sock != -1)
+              success = dontroute(ssh_sock,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_sock != -1)
+              success = no_delay(ssh_sock,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_sock != -1)
+              success = no_delay(ssh_sock,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_sock != -1)
+              success = ck_linger(ssh_sock,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_sock != -1)
+              success = sendbuf(ssh_sock,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_sock != -1)
+              success = recvbuf(ssh_sock,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,4,"","3",xxstring)) < 0) return(x);
+        if ((y = cmcfm()) < 0) return(y);
+        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, n;                     /* 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();
+                  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();
+                  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);
+              if (s == "") s = NULL;
+              if (s) {
+                  s = brstrip(s);
+                  if (s == "") s = NULL;
+              }
+              /* 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 */
+
+          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);
+        }
+        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)));
+          }
+          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 {                        /* 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,
+                   " (bits per second)",
+                   NULL
+                   );
+        } else {
+          ckstrncpy(lp,
+                    "Serial-port speed (bits per second)",
+                    LINBUFSIZ
+                    );
+        }
+        zz = -1L;
+
+#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");
+#ifdef USETCSETSPEED
+            /* 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
+        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;
+            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 */
+
+#ifndef NOPUSH
+#ifdef UNIX
+      case XYWILD:                      /* WILDCARD-EXPANSION */
+        if ((y = cmkey(wildtab,2,
+                       "Who expands wildcards","kermit",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);
+            }
+        }
+        wildxpand = y;
+        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 == 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, NULL)) < 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);
+        if ((x = cmcfm()) < 0) return(x);
+        makestr(&tempdir,s);
+        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 */
+
+#ifdef SESLIMIT
+      case XYLIMIT: {  /* Session-Limit (length of session in seconds) */
+          extern int seslimit;
+#ifdef OS2
+          extern int downloaded;
+#endif /* OS2 */
+          y = cmnum("Maximum length of session, seconds","0",10,&x,xxstring);
+          if (inserver &&
+#ifdef IKSDCONF
+              iksdcf
+#else
+              1
+#endif /* IKSDCONF */
+#ifdef OS2
+               || downloaded
+#endif /* OS2 */
+              ) {
+              if ((z = cmcfm()) < 0)
+                return(z);
+              printf("?Sorry, command disabled.\r\n");
+              return(success = 0);
+          }
+          return(setnum(&seslimit,x,y,86400));
+      }
+#endif /* SESLIMIT */
+
+      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 */
+          char * p = NULL;
+          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 */
+                    if (s == "") s = NULL;
+                    if (s) {
+                        s = brstrip(s);
+                        if (s == "") s = NULL;
+                    }
+                    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 */
+                    if (s == "") s = NULL;
+                    if (s) {
+                        s = brstrip(s);
+                        if (s == "") s = NULL;
+                    }
+                    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 *)
+                            SSL_CTX_new((SSL_METHOD *)TLSv1_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,2,"","", 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;
+            }
+          }
+          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 */
+
+      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
+hupok(x) int x; {                       /* Returns 1 if OK, 0 if not OK */
+    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 */
+			 )) {
+#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
+    int zero;
+#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);
+
+#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 */
diff --git a/ckermit-8.0.211/ckuus4.c b/ckermit-8.0.211/ckuus4.c
new file mode 100644
index 0000000..a47de15
--- /dev/null
+++ b/ckermit-8.0.211/ckuus4.c
@@ -0,0 +1,14091 @@
+#include "ckcsym.h"
+
+/*  C K U U S 4 --  "User Interface" for C-Kermit, part 4  */
+
+/*
+  Authors:
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    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.
+*/
+
+/*
+  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 CK_AUTHENTICATION
+#include "ckuath.h"
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+
+#ifdef VMS
+#include <errno.h>                      /* For \v(errno) */
+extern char * ckvmserrstr(unsigned long);
+#ifndef OLD_VMS
+#include <lib$routines.h>               /* Not for VAX C 2.4 */
+#else
+#include <libdef.h>
+#endif /* OLD_VMS */
+_PROTOTYP(int vmsttyfd, (void) );
+#endif /* VMS */
+
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO                        /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#define APIRET ULONG
+#endif /* NT */
+#include "ckocon.h"
+#include "ckoetc.h"
+int StartedFromDialer = 0;
+HWND hwndDialer = 0;
+LONG KermitDialerID = 0;
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#ifdef CK_PID
+#include <process.h>
+#endif /* CK_PID */
+#endif /* OS2 */
+
+#ifdef KUI
+extern struct keytab * term_font;
+extern int ntermfont, tt_font, tt_font_size;
+#endif /* KUI */
+
+extern xx_strp xxstring;
+
+#ifdef DEC_TCPIP
+#include <descrip>
+#include <dvidef>
+#include <dcdef>
+#endif /* DEC_TCPIP */
+
+#ifdef FNFLOAT
+#include <math.h>                       /* Floating-point functions */
+#endif /* FNFLOAT */
+
+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 */
+
+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;
+#ifdef DEBUG
+extern char debfil[];                   /* Debug log file name */
+extern int debtim;
+#endif /* DEBUG */
+
+extern int noinit;
+
+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 <signal.h>
+#endif /* MAC */
+#endif /* AMIGA */
+
+#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 */
+
+extern char * floname[];
+
+#ifndef NOSPL
+extern int fndiags;                     /* Function diagnostics on/off */
+extern int divbyzero;
+int ispattern = 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[];
+
+/* These need to be internationalized... */
+
+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, 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 long
+  ffc, filcnt, rptn, speed, tfc, tlci, tlco, 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];        /* 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 */
+
+#ifdef OS2ORUNIX
+extern int maxnam, maxpath;             /* Longest name, path length */
+#endif /* OS2ORUNIX */
+
+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 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 */
+#ifdef OS2
+    { "_regname",  VN_REGN,  CM_INV},   /* 1.1.12 */
+    { "_regorg",   VN_REGO,  CM_INV},   /* 1.1.12 */
+    { "_regnum",   VN_REGS,  CM_INV},   /* 1.1.12 */
+#endif /* OS2 */
+    { "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 */
+    { "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 */
+    { "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 OS2ORUNIX
+    { "exedir",    VN_EXEDIR,0},        /* 192 */
+#endif /* OS2ORUNIX */
+    { "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 */
+#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 */
+    { "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 */
+    { "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},
+#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},
+    { "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 */
+    { "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 */
+    { "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 */
+};
+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 */
+    { "crc16",      FN_CRC,  0},        /* CRC-16 */
+#ifdef OS2
+    { "crypt",      FN_CRY, CM_INV},
+#endif /* OS2 */
+    { "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 */
+    { "dayofyear",  FN_JDATE,0},        /* Date to Day of Year */
+    { "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 */
+    { "directories",FN_DIR,  0},        /* List of directories */
+    { "dirname",    FN_DNAM, 0},        /* Directory part of filename */
+    { "dos2unixpath",FN_PC_DU, },       /* DOS to UNIX path */
+    { "dostounixpath",FN_PC_DU, CM_INV}, /* 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 */
+#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 */
+    { "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 */
+    { "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 */
+    { "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 */
+    { "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, 0},        /* MJD to Date */
+    { "mjdtodate",  FN_MJD2, CM_INV},   /* MJD to Date */
+    { "modulus",    FN_MOD,  0},        /* Return modulus of two arguments */
+#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 */
+    { "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 */
+    { "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 */
+    { "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, 0},      /* UNIX to DOS path */
+    { "unixtodospath",FN_PC_UD, CM_INV}, /* 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 */
+
+int fp_rounding = 0;                /* Nonzero if printf("%f") rounds */
+int fp_digits = 0;                  /* Digits of floating point precision */
+
+#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 *
+findinpath(arg) char * arg; {
+#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, z;
+
+    /* Set up search path... */
+#ifdef OS2
+    char * appdata0 = NULL, *appdata1 = NULL;
+#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 */
+    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
+prescan(dummy) int dummy; {             /* Arg is ignored. */
+    extern int howcalled;
+    int yargc; char **yargv;
+    char x;
+    char *yp, *yy;
+#ifdef DEBUG
+    int debcount = 0;
+#endif /* DEBUG */
+    int z;
+
+    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 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 '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 */
+#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");
+                                hwndDialer = (HWND) atol(*yargv);
+                                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 '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 */
+#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");
+                        hwndDialer = (HWND) atol(*yargv);
+                        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 */
+                        hwndDialer = (HWND) atol(*yargv);
+                        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 */
+#endif /* OS2 */
+                    break;
+#ifndef NOICP
+                  case 'Y':             /* No init file */
+                    noinit = 1;
+                    break;
+#endif /* NOICP */
+                  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.
+
+  Translation between two file character sets is done, for example,
+  by the CONNECT, TRANSMIT, and TRANSLATE commands.
+
+  Translation between Kanji character sets is not yet supported.
+*/
+int
+gettcs(cs1,cs2) int cs1, cs2; {
+#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
+doconect(q,async) int q, async; {
+    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;
+    extern int display_demo;
+    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 OS2
+    display_demo = 1;                   /* Remember to display demo */
+#endif /* OS2 */
+
+#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 <user> <password> 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 <user> <password> 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 */
+
+#ifndef NOICP
+#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 252                    /* 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(CR)))
+                  line[i++] = dopar(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] = 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 == IAC && is_tn)
+                          line[i++] = 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
+xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
+
+#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, c2;                       /* Workers */
+#ifndef UNICODE
+    int tcs;
+#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 */
+    extern int nfilc;
+    extern struct keytab fcstab[];
+    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 (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 */
+
+static char hompthbuf[CKMAXPATH+1];
+
+char *
+homepath() {
+    int x;
+    extern char * myhome;
+    char * h;
+
+    h = myhome ? myhome : zhome();
+    hompthbuf[0] = NUL;
+#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
+dolog(x) int x; {
+    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
+pktopn(s,disp) char *s; int disp; {
+    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)
+          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
+traopn(s,disp) char *s; int disp; {
+#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)
+      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
+sesopn(s,disp) char * s; int disp; {
+    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)
+          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
+debopn(s,disp) char *s; int disp; {
+#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)
+          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 */
+}
+
+
+/*  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("<BAD_MONTH>");
+    }
+    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);
+}
+
+#ifndef NOICP
+#ifdef CKLOGDIAL
+
+/*
+  fc = 0 for initial open, meaning open, then close immediately.
+  fc > 0 for subsequent opens, meaning open for use, leave open.
+*/
+int
+diaopn(s,disp,fc) char *s; int disp, fc; {
+    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 *
+shoxm() {
+    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;
+    int i; 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, * ttglckdir();
+        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
+shotcp(n) int n; {
+#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
+shotopt(n) int n; {
+    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
+shotel(n) int n; {
+    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 i, 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_ssleay_is_installed())
+        printf(" SSH V1 and V2 protocols\n");
+    else
+        printf(" SSH V1 and V2 protocols - not available\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
+shods(s) char *s; {                     /* Show a dial-related string */
+    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 *
+pathval(x) int x; {
+    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[];
+#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\n", 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 : "(none)");
+    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 OS2ORUNIX
+    printf(" Longest filename:        %d\n", maxnam);
+    if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+    printf(" Longest pathname:        %d\n", maxpath);
+    if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
+#endif /* OS2ORUNIX */
+
+    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
+    if (protocol != PROTO_K) {
+        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)");
+    }
+#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
+dostat(brief) int brief; {
+    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) {
+            if (docrc)
+              printf(" crc-16 of file(s)      : %ld\n", crc16);
+            else
+              printf(" crc-16 of file(s)      : (disabled)\n");
+            n++;
+        }
+        if (!xferstat && *epktmsg) {
+            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   : %ld\n",ffc);
+        printf(" total file characters  : %ld\n",tfc);
+        n += ftp ? 3 : 4;
+        if (!ftp) {
+            printf(" communication line in  : %ld\n",tlci);
+            printf(" communication line out : %ld\n",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;
+
+/* 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;
+/*
+  timo = How long to wait:
+         < 0 = Wait forever
+           0 = Don't wait
+         > 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 = for now, 1 or 0.  If 1, then don't match anything.
+*/
+int
+doinput(timo,ms,mp,flags) int timo; char *ms[]; int mp[]; int flags; {
+    extern int inintr;
+#ifdef CK_AUTODL
+    extern int inautodl;
+#endif /* CK_AUTODL */
+    int x, y, i, t, rt, icn, anychar, mi[MINPMAX];
+#ifdef GFTIMER
+    CKFLOAT fpt = 0.0;
+#endif /* GFTIMER */
+    int nomatch = 0;
+    int lastchar = 0;
+    int waiting = 0;
+    int imask = 0;
+    char ch, *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 wrapped = 0;
+#ifdef SSHBUILTIN
+    extern int ssh_cas;
+    extern char * ssh_cmd;
+#endif /* SSHBUILTIN */
+
+#define CK_BURST
+/*
+  This 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".
+*/
+#ifdef CK_BURST
+    int burst = 0;                      /* Chars remaining in input burst */
+#endif /* CK_BURST */
+
+    imask = cmask;
+    if (parity) imask = 0x7f;
+    inwait = timo;                      /* For \v(inwait) */
+    nomatch = flags & 1;
+    makestr(&inpmatch,NULL);
+
+    if (!matchbuf) {
+        matchbuf = malloc(MATCHBUFSIZ+1);
+        matchbuf[0] = NUL;
+    }
+    matchindex = 0;
+
+    is_tn =
+#ifdef TNCODE
+        (local && network && IS_TELNET()) || (!local && sstelnet)
+#else
+         0
+#endif /* TNCODE */
+          ;
+
+    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
+    if ( network && nettype == NET_SSH && ssh_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]) {                       /* If we were passed a NULL pointer */
+        anychar = 1;                    /*  ... */
+    } else {
+        y = (int)strlen(ms[0]);         /* Or if search string is empty */
+        anychar = (y < 1);              /* any input character will do. */
+    }
+    if (flags & 1) anychar = 0;		/* Don't match anything */
+
+    if (!anychar && waiting == 0 && timo == 0)
+      return(0);
+
+
+#ifndef NODEBUG
+    if (deblog) {
+        char xbuf[24];
+        debug(F101,"doinput anychar","",anychar);
+        debug(F101,"doinput timo","",timo);
+        debug(F101,"doinput echo","",inecho);
+        debug(F101,"doinput burst","",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++)
+      mi[y] = 0;                        /* String pattern match position */
+
+    if (!inpcas[cmdlvl]) {              /* INPUT CASE = IGNORE?  */
+        y = -1;
+
+        while ((xp = ms[++y])) {
+            while (*xp) {               /* Convert to lowercase */
+                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 */
+                      default: continue;
+                    }
+                  case 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 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. */
+                    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) */
+
+            /* Don't NUL-terminate here - it's a circular buffer. */
+
+            if (inpbp >= inpbuf + inbufsize) { /* Time to wrap around? */
+                wrapped++;
+                *inpbp = NUL ;          /* Make it null-terminated */
+                inpbp = inpbuf;         /* Yes. */
+            }
+            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) {
+#ifdef UNIX
+                if (sessft != 0 || c != '\r')
+#else
+#ifdef OSK
+                if (sessft != 0 || c != '\012')
+#endif /* OSK */
+#endif /* UNIX */
+                  sesbuf[sescnt++] = c; /* Buffer session log output */
+            }
+#endif /* OS2 */
+            if (anychar) {              /* Any character will do? */
+                x = 1;
+                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;
+                            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;
+                        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;
+                    x = 1;              /* Yes, */
+                    break;              /* done. */
+                }
+                mi[y] = i;              /* No, remember match-position */
+            }
+            if (x == 1) {               /* Set \v(minput) result */
+                m_found = y + 1;
+                break;
+            }
+        }
+#ifdef CK_BURST
+        else if (y <= -1 && burst > 0) {
+            debug(F111,"doinput (y<=-1&&burst>0)","burst",burst);
+                                        /* a timo 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
+        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. */
+    if (nomatch) x = 1;			/* Succeed if nomatch and timed out. */
+    myflsh();                           /* Flush buffered output. */
+    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 (!nomatch)
+      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
+doreinp(timo,s,pat) int timo; char *s; int pat; {
+    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
+yystring(s,s2) char *s; char **s2; {    /* Reverse a string */
+    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 *
+getip(s) char *s; {
+    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 *
+zjdate(date) char * date; {             /* date = yyyymmdd */
+    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 *
+jzdate(date) char * date; {             /* date = yyyyddd */
+    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.
+*/
+long
+mjd(date) char * date; {
+    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
+static char ** flist = (char **) NULL;  /* File list for \fnextfile() */
+static int flistn = 0;                  /* Number of items in file list */
+
+/*
+  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 *
+fpformat(fpresult,places,round) CKFLOAT fpresult; int places, round; {
+    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
+evalerr(fn) char * fn; {
+    if (fndiags) {
+        if (divbyzero)
+          ckmakmsg(fnval,FNVALL,"<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
+        else
+          ckmakmsg(fnval,FNVALL,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+    }
+}
+
+char *
+dokwval(s,sep) char * s, sep; {
+    char c = '\0', * p, * kw = NULL, * vp = NULL;
+    int x;
+    if (!s) return("0");
+    if (!*s) return("0");
+    debug(F110,"kwval arg",s,0);
+    debug(F110,"kwval sep",ckctoa(sep),0);
+    p = (char *)malloc((int)strlen(s)+1);
+    if (!p) return("0");
+    strcpy(p,s);                        /* SAFE */
+    s = p;
+    while (*s < '!' && *s > '\0')       /* Get first nonblank */
+      s++;
+    if (!*s) return("0");
+    if (*s == sep) return("0");
+    kw = s;                             /* Keyword */
+    while (*s > ' ') {
+        if (*s == sep) {                /* keyword=... */
+            c = *s;
+            break;
+        }
+        s++;
+    }
+    *s++ = NUL;                         /* Terminate keyword */
+    while (*s < '!' && *s > '\0')       /* Skip blanks */
+      s++;
+    if (!c && *s == sep) {
+        c = *s++;                       /* Have separator */
+        while (*s < '!' && *s > '\0')   /* Skip blanks */
+          s++;
+    }
+    if (c) {
+        vp = s;
+        while (*s > ' ')                /* Skip to end */
+          s++;
+        *s = NUL;                       /* Terminate value */
+    }
+    debug(F110,"kwval c",ckctoa(c),0);
+    debug(F110,"kwval keyword",kw,0);
+    debug(F110,"kwval value",vp,0);
+    x = c ? addmac(kw,vp) : -1;
+    free(p);
+    return((x < 0) ? "0" : "1");
+}
+
+static int
+isaarray(s) char * s; {			/* Is s an associative array element */
+    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);
+}
+
+static char *                           /* Evaluate builtin functions */
+fneval(fn,argp,argn,xp) char *fn, *argp[]; int argn; char * xp; {
+    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,"<ERROR:NO_SUCH_FUNCTION:\\f%s()>",fn);
+                else
+                  sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION>");
+                break;
+              case -2:
+                if (x + 26 < FNVALL)
+                  sprintf(fnval,"<ERROR:NAME_AMBIGUOUS:\\f%s()>",fn);
+                else
+                  sprintf(fnval,"<ERROR:NAME_AMBIGUOUS>");
+                break;
+              case -3:
+                sprintf(fnval,"<ERROR:FUNCTION_NAME_MISSING:\\f()>");
+                break;
+              default:
+                if (x + 26 < FNVALL)
+                  sprintf(fnval,"<ERROR:LOOKUP_FAILURE:\\f%s()>",fn);
+                else
+                  sprintf(fnval,"<ERROR:LOOKUP_FAILURE>");
+                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,"<ERROR:MISSING_ARG:\\f%s()>",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;
+        if (!(p = argp[0]) || !*p) {
+            failed = 1;
+            p = fnval;
+            if (fndiags)
+              sprintf(fnval,"<ERROR:MISSING_ARG:\\fcontents()>");
+            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,"<ERROR:ARG_BAD_VARIABLE:\\fcontents()>");
+                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,"<ERROR:OVERFLOW:\\fcontents()>");
+		    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,"<ERROR:ARG_BAD_ARRAY:\\fcontents()>");
+                goto fnend;
+            }
+            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];    /* get data pointer */
+                    if (ap) {           /* and if there is one */
+                        p = ap[d];
+                        goto fnend;
+                    }
+                }
+            } else {
+                failed = 1;
+                p = fnval;
+                if (fndiags)
+                  sprintf(fnval,"<ERROR:ARG_NOT_ARRAY:\\fcontents()>");
+                goto fnend;
+            }
+        } else {
+            failed = 1;
+            p = fnval;
+            if (fndiags)
+              sprintf(fnval,"<ERROR:ARG_NOT_VARIABLE:\\fcontents()>");
+            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,"<ERROR:MALLOC_FAILURE:\\f",fn,"()>",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,
+                           "<ERROR:ARG_TOO_LONG:\\f",fn,"()>",NULL);
+                else
+                  ckmakmsg(fnval,FNVALL,
+                           "<ERROR:ARG_EVAL_FAILURE:\\f",fn,"()>",NULL);
+            }
+            goto fnend;
+        }
+        debug(F111,"fneval arg",bp[i],i);
+    }
+
+#ifdef DEBUG
+    if (deblog) {
+        int j;
+        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 */
+/*
+  From this point on, bp[0..argn-1] are not NULL and all must be freed
+  before returning.
+*/
+    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:
+          case FN_KWVAL:
+#ifdef COMMENT
+          case FN_SLEEP:
+          case FN_MSLEEP:
+#endif /* COMMENT */
+#ifdef NT
+          case FN_SNAME:
+          case FN_LNAME:
+#endif /* NT */
+            failed = 1;
+            p = fnval;
+            if (fndiags)
+              ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",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,
+                            "<ERROR:NO_SUCH_MACRO:\\f",fn,"(",p2,")>",
+                            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++) {
+                    strncat(p,bp[i],MAXARGLEN);
+                    strncat(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 */
+              xflags |= ZX_DIRONLY;
+#ifdef OS2
+              zxpn = 1;                 /* Use the alternate list */
+#endif /* OS2 */
+          } else {                      /* List only files */
+              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,
+                         "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",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) */
+      case FN_RIX:                      /* \frindex(s1,s2,start) */
+      case FN_SEARCH:                   /* \fsearch(pat,string,start) */
+      case FN_RSEARCH: {                /* \frsearch(pat,string,start) */
+        int i = 0, right = 0, search = 0;
+        right = (cx == FN_RIX || cx == FN_RSEARCH);
+        search = (cx == FN_SEARCH || cx == FN_RSEARCH);
+        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 (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 (search) {               /* \fsearch() or \frsearch() */
+                if (right && pat[0] == '^') {
+                    right = 0;
+                    start = 0;
+                }
+                if (right) {
+                    if (start < 0) start = len2 - 1;
+                    for (i = start;
+                         i >= 0 && !ckmatch(pat,s+i,inpcas[cmdlvl],1+4);
+                         i--) ;
+                    if (i < 0) i = 0; else i++;
+                } else {
+                    i = ckmatch(pat,&s[start],inpcas[cmdlvl],1+4);
+                    if (start > 0) i += start;
+                }
+            } else {
+                i = ckindex(pat,bp[1],start,right,inpcas[cmdlvl]);
+            }
+            sprintf(fnval,"%d",i);      /* SAFE */
+            p = fnval;
+        }
+        goto fnend;
+      }
+
+      case FN_RPL:                      /* \freplace(s1,s2,s3) */
+      /*
+        s = bp[0] = source string
+            bp[1] = match string
+            bp[2] = replacement string
+            bp[3] = which occurrence (default = all);
+        p = fnval = destination (result) string
+      */
+        if (argn < 1)                   /* Nothing */
+          goto fnend;
+        if (argn < 2) {                 /* Only works if we have 2 or 3 args */
+            ckstrncpy(p,bp[0],FNVALL);
+        } else {
+            int occur = 0, xx = 0, j2;
+            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;
+            j2 = j;
+            if (argn > 3) {
+                if (chknum(bp[3])) {
+                    occur = atoi(bp[3]);
+                } else {
+                    failed = 1;
+                    if (fndiags)
+                      ckmakmsg(fnval,FNVALL,
+                               "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+                    goto fnend;
+                }
+            }
+            /* 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 string */
+                while (j-- > 0) {       /* For each character */
+                    if (!ckstrcmp(bp[1],s,len2,inpcas[cmdlvl]) &&
+                        (occur == 0 || occur == ++xx)) {
+                        if (len3) {
+                            ckstrncpy(p,bp[2],FNVALL);
+                            p += len3;
+                        }
+                        s += len2;      /* and skip past it. */
+                    } else {            /* No, */
+                        *p++ = *s++;    /* just copy this character */
+                    }
+                }
+                *p = NUL;
+                while ((*p++ = *s++));
+                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,
+                           "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+            }
+        } else {
+            failed = 1;
+            evalerr(fn);
+        }
+        goto fnend;
+
+      case FN_COD:                      /* \fcode(char) */
+        if ((int)strlen(bp[0]) > 0) {
+            p = fnval;
+            i = *bp[0];
+            sprintf(p,"%d",(i & 0xff)); /* SAFE */
+        } else p = "0";			/* Can't happen */
+        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,
+                                   "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",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,
+                         "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",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,
+                               "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",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,"<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
+            goto fnend;
+        }
+        ckstrncpy(fnval,s,FNVALL);
+#endif /* ZFCDAT */
+        goto fnend;
+
+    } /* Break up big switch... */
+
+    switch (y) {
+      case FN_FS:                       /* \fsize(filename) */
+        p = fnval;
+        z = zchki(bp[0]);
+        if (z < 0) {
+            failed = 1;
+            if (fndiags) {
+                if (z == -1)
+                  ckmakmsg(fnval,FNVALL,
+                           "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
+                else if (z == -2)
+                  ckmakmsg(fnval,FNVALL,
+                           "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
+                else if (z == -3)
+                  ckmakmsg(fnval,FNVALL,
+                           "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
+                else
+                  ckmakmsg(fnval,FNVALL,
+                           "<ERROR:FILE_ERROR:\\f",fn,"()>",NULL);
+            }
+            goto fnend;
+        }
+        sprintf(fnval,"%ld",z);         /* SAFE */
+        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,
+                               "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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 = (char *) 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,
+			   "<ERROR:OVERFLOW:\\f",fn,"()>",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,
+                                     "<ERROR:ARG_OUT_OF_RANGE:\\f",
+                                     fn,
+                                     "()>",
+                                     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,
+                             "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,
+                             "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,
+                             "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,
+                                 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,
+                                 "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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 (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 == 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,
+                         "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",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) */
+        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];
+        x = 0;
+        while (*s++) {
+            if (*(s-1) == c) {
+                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<<i)) {
+                              if (s[0] == gr_opn[i] && s[x-1] == gr_cls[i]) {
+                                  ckstrncpy(fnval,s+1,FNVALL);
+                                  fnval[x-2] = NUL;
+                                  goto fnend;
+                              }
+                          }
+                      }
+                      ckstrncpy(fnval,s,FNVALL); /* No match */
+                      goto fnend;
+                  }
+              }
+          }
+          c = *bp[1];
+          if (!c) c = s[0];
+          if (argn > 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,
+                           "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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 */
+
+          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,
+                           "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,
+                           "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,
+                         "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",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,
+                             "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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);
+
+          wordnum = q ? q->a_size : -1; /* Check result */
+          if (wordnum < 0) {
+              failed = 1;               /* Failure */
+              if (fndiags)
+                ckmakmsg(fnval,FNVALL,
+                         (wordnum == -1) ?
+                         "<ERROR:MALLOC_FAILURE:\\f" :
+                         "<ERROR:TOO_MANY_WORDS:\\f",
+                         fn,
+                         "()>",
+                         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,
+                                 "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",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,
+                         "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+              goto fnend;
+          }
+          if (kv != 4 && kv != 5) {
+              failed = 1;
+              if (fndiags)
+                ckmakmsg(fnval,FNVALL,
+                         "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,"<ERROR:MISSING_ARG:\\f",fn,"()>",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,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",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)
+            max = 0;
+          failed = 0;                   /* Unset failure flag */
+          sprintf(fnval,"%d",max);      /* SAFE */
+          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,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
+        }
+        goto fnend;
+
+      case FN_DATEJ:
+        ckstrncpy(fnval,jzdate(bp[0]),FNVALL); /* Convert to yyyy<dayofyear> */
+        p = fnval;                      /* Point to result */
+        failed = 0;
+        if (*p == '-') {
+            failed = 1;
+            if (fndiags)                /* Default is this error message */
+              ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",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 */
+        p = ckcvtdate(p,2);             /* Convert to standard form */
+        if (*p == '<') {
+            failed = 1;
+            if (fndiags)                /* Default is this error message */
+              ckmakmsg(fnval,FNVALL,
+                       "<ERROR:ARG_BAD_DATE_OR_TIME:\\f",fn,"()>",NULL);
+            p = fnval;
+            goto fnend;
+        }
+        if (argn > 1) {
+            s = bp[1];
+            if (!s) s = "";
+            if (!*s) s = "0";
+            if (!chknum(s)) {
+                failed = 1;
+                if (fndiags)
+                  ckmakmsg(fnval,FNVALL,
+                           "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",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 */
+          extern char * pncvt();
+          failed = 0;
+          p = pncvt(bp[0]);
+          if (!p) p = "";
+          if (!*p) {
+            failed = 1;
+            if (fndiags)                /* Default is this error message */
+              ckmakmsg(fnval,FNVALL,
+                       "<ERROR:ARG_BAD_PHONENUM:\\f",fn,"()>",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,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",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,
+                       "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,
+                         "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,
+                             "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
+                  else if (z == -2)
+                    ckmakmsg(fnval,FNVALL,
+                             "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
+                  else if (z == -3)
+                    ckmakmsg(fnval,FNVALL,
+                             "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
+                  else
+                    ckmakmsg(fnval,FNVALL,
+                             "<ERROR:FILE_ERROR:\\f",fn,"()>",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,"<ERROR:MISSING_ARG:\\f",fn,"()>",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,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",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,
+                         "<ERROR:ARG_INCOMPLETE:\\f",fn,"()>",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,"<ERROR:",m,"\\f",fn) > 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,
+                         "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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;
+          extern int xdelmac();
+          p = fnval;
+          if (argn < 2) {
+              if (fndiags)
+                ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG2:\\f",fn,"()>",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,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",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,"<ERROR:ASSOCIATIVE_ARRAY:\\f",fn,"()>",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, j, places = 0;
+        int argcount = 1;
+
+        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,
+                               "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",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,
+                                   "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",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,
+                           "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",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,
+                           "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,
+                           "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,
+                           "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,
+                       "<ERROR:FLOATING-POINT-OP:\\f",fn,"()>",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,
+                       "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+            failed = 0;
+            ckstrncpy(fnval,ckferror(x),FNVALL);
+            goto fnend;
+        }
+        if (argn < 1) {                 /* All file functions need channel */
+            if (fndiags)
+              ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",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,
+                       "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+            goto fnend;
+        }
+        if (channel < 0 || channel > z_maxchan) { /* Check channel range */
+            if (fndiags)
+              ckmakmsg(fnval,FNVALL,
+                       "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,"<ERROR:FILE_NOT_OPEN:\\f",fn,"()>",NULL);
+            goto fnend;
+        }
+        switch (y) {                    /* Do the requested function */
+          case FN_FPOS:                 /* Get position */
+            z = z_getpos(channel);
+            sprintf(fnval,"%ld",z);     /* SAFE */
+            goto fnend;
+
+          case FN_NLINE:                /* Get line number */
+            z = z_getline(channel);
+            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,
+                           "<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
+                goto fnend;
+            }
+            if (rdigits(bp[1])) {
+                t = atoi(bp[1]);
+            } else {
+                if (fndiags)
+                  ckmakmsg(fnval,FNVALL,
+                           "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,
+                           "<ERROR:FILE_ERROR_%d:\\f",fn,"()>",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_PATTERN) {             /* \fpattern() */
+        ispattern = 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,
+                       "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,
+                       "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,
+                               "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,
+                           "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
+            goto fnend;
+        }
+        if (!rdigits(bp[1]) || !rdigits(bp[2])) {
+            if (fndiags)
+              ckmakmsg(fnval,FNVALL,
+                       "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+            goto fnend;
+        }
+        p = ckradix(bp[0],atoi(bp[1]),atoi(bp[2]));
+        if (!p) {
+            if (fndiags)
+              ckmakmsg(fnval,FNVALL,
+                       "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
+            goto fnend;
+        }
+        failed = 0;
+        ckstrncpy(fnval,p,FNVALL);
+        p = fnval;
+        goto fnend;
+    }
+    if (cx == FN_JOIN) {
+        int i, x, y, z, flag, 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 */
+
+        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,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",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 */
+        if (argn > 1)
+          if (bp[1])
+            if (*bp[1])
+              sep = bp[1];
+        lb[0] = NUL;
+        rb[0] = NUL;
+        lb[1] = NUL;
+        rb[1] = NUL;
+        if (argn > 2) {                 /* 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,
+                           "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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 (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;                   /* Buffer overrun flag */
+            if (grouping) {             /* Does this element need quoting? */
+                q = s;                  /* Look for spaces */
+                while ((c = *q++)) { if (c == SP) { flag++; break; } }
+            }
+            y = strlen(s);              /* Get length of this element */
+            if (cx == 0 && grouping)    /* If empty it might need quoting */
+              flag = 1;
+            if (flag) {                 /* Add grouping if needed */
+                char * s2 = NULL;
+                y += 2;
+                if ((q = (char *)malloc(y+1))) {
+                    ckmakmsg(q,y+1,(char *)lb,s,(char *)rb,NULL);
+                    makestr(&s2,q);
+                    free(q);
+                    s = s2;
+                }
+            }
+            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 (z < y)                  /* 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,
+                           "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",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,
+                       "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",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,
+                                   "<ERROR:BAD_RANGE:\\f",fn,"()>",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,
+                                   "<ERROR:BAD_RANGE:\\f",fn,"()>",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,
+                           "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",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,
+                       "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",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,"<ERROR:BAD_DATE:\\f",fn,"()>",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,"<ERROR:BAD_DATE:\\f",fn,"()>",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 * d1, * 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,"<ERROR:BAD_DATE:\\f",fn,"()>",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) ?
+                         "<ERROR:BAD_DELTA_TIME:\\f" :
+                         "<ERROR:OVERFLOW:\\f",
+                       fn,
+                       "()>",
+                       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,
+                         "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
+                p = fnval;
+            }
+            goto fnend;
+        }
+        if (cx == FN_SLEEP)
+          x *= 1000;
+        msleep(x);
+        goto fnend;
+    }
+#endif /* COMMENT */
+
+#ifdef NT
+    if (cx == FN_SNAME) {
+        GetShortPathName(bp[0],fnval,FNVALL);
+        goto fnend;
+    }
+    if (cx == FN_LNAME) {
+        ckGetLongPathName(bp[0],fnval,FNVALL);
+        goto fnend;
+    }
+#endif /* NT */
+
+/* Note: when adding new functions remember to update dohfunc in ckuus2.c. */
+
+    failed = 1;
+    if (fndiags)
+      ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN_FUNCTION:\\f",fn,"()>",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,"<ERROR:BAD_ARG:\\f",fn,"()>",NULL);
+                p = fnval;
+            }
+        } else {
+            ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN:\\f",fn,"()>",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
+#define getpid _getpid
+    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 */
+nvlook(s) char *s; {
+    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,"<ERROR:NO_SUCH_VARIABLE:\\v(%s)>",s); /* SAFE */
+        else
+          sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE>"); /* 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_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, "%ld", ffc);     /* SAFE */
+        return(vvbuf);
+
+      case VN_TFC:                      /* Size of most recent file group */
+        sprintf(vvbuf, "%ld", 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
+        return("unknown");
+#endif /* CK_UTSNAME */
+#endif /* CKCPU */
+#endif /* OS2 */
+
+      case VN_CMDL:                     /* Command level */
+        sprintf(vvbuf, "%d", cmdlvl);   /* SAFE */
+        return(vvbuf);
+
+      case VN_DAY:                      /* Day of week */
+        ztime(&p);
+        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_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 */
+#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
+          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);
+
+#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)
+                  ckstrncpy(vvbuf,"tcp/ip_ssl",VVBUFL);
+                else if (ttnproto == NP_TLS)
+                  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: {
+          unsigned long 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
+        {
+            extern char * whoami();     /* From ckufio.c... */
+#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) {
+            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 */
+        }
+        ckstrncpy(vvbuf,p,VVBUFL);
+        p = vvbuf;
+
+/* This needs generalizing for VOS, AOS/VS, etc... */
+
+        while (*p) {
+#ifdef OS2
+            if (*p == '\\') *p = '/';
+#endif /* OS2 */
+            p++;
+        }
+#ifndef VMS
+        if (p > vvbuf) {
+            char c =                    /* Directory termination character */
+#ifdef MAC
+              ':'
+#else
+#ifdef datageneral
+              ':'
+#else
+#ifdef STRATUS
+              '>'
+#else
+              '/'
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* MAC */
+                ;
+
+            if (*(p-1) != c) {
+                *p++ = c;
+                *p = NUL;
+            }
+        }
+#endif /* VMS */
+        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,"%d",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 */
+
+#ifdef OS2
+      case VN_REGN:
+        return(get_reg_name());
+      case VN_REGO:
+        return(get_reg_corp());
+      case VN_REGS:
+        return(get_reg_sn());
+#endif /* OS2 */
+    } /* 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:
+        return((char *)versio);
+
+      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 char * krb4_errno;
+        sprintf(vvbuf,"%d",krb4_errno); /* SAFE */
+        return((char *)vvbuf);
+      }
+      case VN_K5ENO: {
+        extern char * 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[];
+          int y = VVBUFL - 1;
+          char * s = unm_mod;
+#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:<tab><tab>"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: {
+          extern char * getdm();
+          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 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 */
+          extern int ftpisconnected();
+          return(ftpisconnected() ? "1" : "0");
+      }
+      case VN_FTP_L: {                  /* FTP Logged in */
+          extern int ftpisloggedin();
+          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_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
+    }
+
+#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 = (char *)GetPersonal();
+        if (p) {
+            GetShortPathName(p,vvbuf,VVBUFL);
+            return(vvbuf);
+        }
+        return("");
+      case VN_DESKTOP:
+          p = (char *)GetDesktop();
+          if (p) {
+              GetShortPathName(p,vvbuf,VVBUFL);
+              return(vvbuf);
+          }
+          return("");
+      case VN_COMMON:
+        p = (char *)GetAppData(1);
+        if (p) {
+            ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
+            GetShortPathName(vvbuf,vvbuf,VVBUFL);
+            return(vvbuf);
+        }
+        return("");
+      case VN_APPDATA:
+        p = (char *)GetAppData(0);
+        if (p) {
+            ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
+            GetShortPathName(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)
+          ckstrncpy(embuf,"<ERROR:NO_SUCH_VARIABLE>",EMBUFLEN);
+        printf("?%s\n",embuf);
+        return((char *)embuf);
+    } else
+      return("");
+}
+#endif /* NOSPL */
+
+
+/*
+  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 (to prevent overruns).
+  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.
+*/
+
+#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
+zzstring(s,s2,n) char *s; char **s2; int *n; {
+    int x,                              /* Current character */
+        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 */
+
+    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;
+
+    new = *s2;                          /* for one less level of indirection */
+#ifdef COMMENT
+    old = new;
+#endif /* COMMENT */
+
+#ifndef NOSPL
+    ispattern = 0;                      /* For \fpattern() */
+    isjoin = 0;				/* For \fjoin() */
+#endif /* NOSPL */
+    depth++;                            /* Sink to a new depth */
+    if (depth > XXDEPLIM) {             /* Too deep? */
+        printf("?definition is circular or too deep\n");
+        debug(F101,"zzstring fail","",depth);
+        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 */
+                debug(F010,"zzstring %n vp",vp,0);
+                if (zzstring(vp,&new,&n2) < 0) { /* call self to evaluate it */
+                    debug(F101,"zzstring fail 6","",depth);
+#ifdef DVNAMBUF
+                    if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+                    return(-1);         /* Pass along failure */
+                }
+#ifdef COMMENT
+            } else {
+                debug(F110,"zzstring %n vp","(NULL)",0);
+                n2 = nx;
+                new = old;
+                *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. */
+
+            x = chkarray(vbi,d);        /* Array is declared? */
+            debug(F101,"zzstring chkarray","",x);
+            if (x > 0) {
+#ifdef COMMENT
+                char * s1 = NULL;
+#endif /* COMMENT */
+                vbi -= ARRAYBASE;       /* Convert name to index */
+
+#ifdef COMMENT
+                if (vbi == 0) {         /* Argument vector array */
+                    extern char ** toparg, ** m_xarg[];
+                    extern int n_xarg[];
+                    if (maclvl < 0) {
+                        if (topargc >= d) {
+                            s1 = toparg[d];
+                        }
+                    } else {
+                        if (n_xarg[maclvl] >= d) {
+                            s1 = m_xarg[maclvl][d];
+                        }
+                    }
+                    if (s1) {
+                        if (zzstring(s1,&new,&n2) < 0) { /* evaluate */
+                            debug(F101,"zzstring fail 7.5","",depth);
+#ifdef DVNAMBUF
+                            if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+                            return(-1); /* Pass along failure */
+                        }
+                    } else {
+                        /* old = new; */
+                        n2 = nx;
+                    }
+                } else
+#endif /* COMMENT */
+                  if (a_dim[vbi] >= d) { /* If subscript in range */
+                    char **ap;
+#ifndef COMMENT
+                    debug(F110,"zzstring a_ptr[vbi]",a_ptr[vbi],0);
+                    debug(F110,"zzstring a_ptr[vbi][d]",a_ptr[vbi][d],0);
+#endif /* COMMENT */
+                    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 (zzstring(ap[d],&new,&n2) < 0) { /* evaluate */
+                                debug(F101,"zzstring fail 8","",depth);
+#ifdef DVNAMBUF
+                                if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+                                return(-1); /* Pass along failure */
+                            }
+                        }
+                    } else {
+                        /* old = new; */
+                        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 */
+            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 '$':                     /* 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 */
+            while (y++ < VNAML) {       /* Watch out for name too long */
+                if (*p == '(') {        /* Parens can be nested... */
+                    pp++;
+                } else if (*p == ')') { /* Name properly terminated with ')' */
+                    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. */
+            }
+            s = p;                      /* Adjust global source pointer */
+            s3 = vnambuf;
+            x3 = 0;
+            while (*s3++) x3++;
+            p = malloc(x3 + 1);         /* Make temporary space */
+            if (p) {                    /* 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;
+            }
+            debug(F110,"zzstring vname",vnambuf,0);
+            q = NULL;
+            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;
+                k = strlen(vnambuf);
+                /* \s(name[n:m]) -- Compact substring notation */
+                if ((x == 's' || x == ':') && (k > 1)) { /* Substring wanted */
+                    if (vnambuf[k-1] == ']') {
+                        int i;
+                        for (i = k-1; i > 0; i--) {
+                            if (vnambuf[i] == '[') {
+                                char * p = NULL;
+                                p = (char *)malloc(k - i + 8);
+                                if (p) {
+                                    /* Now this is a dirty trick... */
+                                    ckmakmsg(p,
+                                             k-i+8,
+                                             "\\&a",
+                                             &vnambuf[i],
+                                             NULL,
+                                             NULL
+                                             );
+                                    arraybounds(p,&x1,&x2);
+                                    if (x1 < 1) x1 = 1;
+                                    x1--; /* Adjust to 0-base */
+                                    free(p);
+                                    vnambuf[i] = NUL;
+                                }
+                            }
+                        }
+                    }
+                }
+                if (x == ':') {
+                    vp = vnambuf;
+                } else {
+		    y = isaarray(vnambuf) ?
+			mxxlook(mactab,vnambuf,nmac) :
+			mxlook(mactab,vnambuf,nmac);
+                    if (y > -1) {	/* Got definition */
+                        vp = mactab[y].mval;
+                    } else {
+                        vp = NULL;
+                    }
+                }
+                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);
+                            if (x1 > k) {  /* If it's off the end, */
+                                vp = NULL; /* result is empty */
+                            } else if (k > 0) {
+                                if ((q = malloc(k+1))) {
+                                    strcpy(q,vp); /* safe */
+                                    if ((x2 > -1) && ((x1 + x2) <= k)) {
+                                        q[x1+x2] = NUL;
+                                    }
+                                    vp = q+x1;
+                                }  else vp = NULL;
+                            } else vp = NULL;
+                        }
+#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 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 */
+
+        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 */
+    debug(F010,"zzstring while exit",*s2,0);
+
+    depth--;                            /* Adjust stack depth gauge */
+    *s2 = new;                          /* Copy results back into */
+    *n = n2;                            /* the argument addresses */
+    debug(F101,"zzstring ok","",depth);
+#ifdef DVNAMBUF
+    if (vnambuf) free(vnambuf);
+#endif /* DVNAMBUF */
+    return(0);                          /* and return. */
+}
+#endif /* NOICP */
diff --git a/ckermit-8.0.211/ckuus5.c b/ckermit-8.0.211/ckuus5.c
new file mode 100644
index 0000000..6110629
--- /dev/null
+++ b/ckermit-8.0.211/ckuus5.c
@@ -0,0 +1,11913 @@
+#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 <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    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 */
+
+#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 */
+
+#ifdef OS2
+#include "ckoetc.h"
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else /* NT */
+#include <windows.h>
+#define TAPI_CURRENT_VERSION 0x00010004
+#include <tapi.h>
+#include <mcx.h>
+#include "ckntap.h"
+#define APIRET ULONG
+extern int DialerHandle;
+extern int StartedFromDialer;
+#endif /* NT */
+#include "ckocon.h"
+#include "ckokey.h"
+#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[] ;
+#endif /* OS2 */
+
+/* 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;
+
+#ifdef LOCUS
+extern int locus, autolocus;
+#endif /* LOCUS */
+
+#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 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;
+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 long 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 */
+#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
+char * ckprompt = "(\\v(dir)) C-Kermit>"; /* Default prompt for others */
+char * ikprompt = "(\\v(dir)) IKSD>";
+#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 */
+#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_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];
+int tfline[MAXTAKE];
+
+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 noherald = 0;
+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;
+#else
+int xquiet[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";
+#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";
+#endif /* CK_SPEED */
+
+#ifdef VMS
+char *m_purge = "run purge \\%*";
+#endif /* VMS */
+
+#ifdef OS2
+char *m_manual = "browse \\v(exedir)docs/manual/kermit95.htm";
+#endif /* OS2 */
+
+/* Now the multiline macros, defined with addmmac()... */
+
+/* FOR macro for \%i-style loop variables (see dofor()...) */
+
+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)",
+""};
+
+/* This is the FOR macro when the loop variable is itself a macro */
+
+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)",
+""};
+
+/* WHILE macro */
+char *whil_def[] = { "_assign _whi\\v(cmdlevel) {_getargs,",
+":_..inc,\\%1,\\%2,goto _..inc,:_..bot,_putargs},",
+"_def break goto _..bot, _def continue goto _..inc,",
+"do _whi\\v(cmdlevel),_assign _whi\\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)",
+""};
+
+/*
+  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
+    { "personal", VN_PERSONAL,  0 },
+#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 long expon, (long, long) );
+_PROTOTYP( static long gcd, (long, long) );
+_PROTOTYP( static long fact, (long) );
+
+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;
+    }
+#endif /* TTSPDLIST */
+
+#ifndef NOSPL
+    /* Allocate INPUT command buffer */
+    if (!inpbuf) {
+        if (!(inpbuf = (char *) malloc(INPBUFSIZ+1)))
+          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 (!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;
+#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;
+        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;
+#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(F110,"CUSTOM 1",line,0);
+    if (!line[0] || zchki(line) < 0) {
+	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;
+        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;
+        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;
+            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;
+#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
+        GetShortPathName(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;
+#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;
+#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
+getncm(s,n) char *s; int n; {
+    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,"XXX getncm eom","",0); */
+        popclvl();                      /* pop command level. */
+        return(-1);
+    } else {                            /* otherwise, tack CR onto end */
+        *s++ = CR;
+        *s = '\0';
+        /* debug(F110,"XXX 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
+domac(name, def, flags) char *name, *def; int flags; {
+    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
+getnct(s,n,f,flag) char *s; int n; FILE *f; int flag; {
+    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 */
+
+    s2 = s;                             /* Remember original pointer */
+    prev = s2;
+    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]\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 */
+        }
+#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, */
+          printf("%3d. %s",             /* echo it this line. */
+#ifndef NODIAL
+                 flag ? dirline :
+#endif /* NODIAL */
+                 tfline[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 > 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 */
+    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);
+}
+
+
+/*  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
+parser(m) int m; {
+    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;
+#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 */
+
+    debok = 1;                          /* Undisable debugging */
+
+#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 && !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");
+        printf("(Use SET HINTS OFF to suppress hints.)\n");
+        printf("*************************\n\n");
+    }
+    debug(F101,"topcmd","",topcmd);
+    if (getcmd && !success && hints && !interrupted && !fatalio && !xcmdsrc) {
+        int x = 0;
+        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);
+        }
+#ifdef UNIX
+        if (errno != 0)
+#endif /* UNIX */
+          printf(" Most recent local error: \"%s\"\n",ck_errstr());
+        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"
+               );
+        printf("Also:\n");
+        printf(" . Be sure the target directory has write permission.\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 */
+        xaskmore = saveask;             /* Restore global more-prompting */
+        diractive = 0;
+        cdactive = 0;
+
+#ifndef NOSPL
+        askflag = 0;
+#endif /* NOSPL */
+
+    /* 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);
+
+#ifdef RECURSIVE
+            /* In case of "send /recursive ./?<Ctrl-U>" 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) {
+                        printf("\n?Invalid - \"%s\"\n",cmdbuf);
+#ifdef COMMENT
+#ifndef NOSPL
+                        if (maclvl > -1 && xcmdsrc == 2)
+                          printf("Macro: %s; ",
+                                 m_arg[maclvl][0] ?
+                                 m_arg[maclvl][0] : "");
+#endif /* NOSPL */
+                        if (tlevel > -1) {
+                            printf("Command file: %s, line %d\n",
+                                   tfnam[tlevel] ? tfnam[tlevel] : "",
+                                   tfline[tlevel]
+                                   );
+                        }
+#else
+                        if (xcmdsrc > 0) {
+                            printf("Command stack:\n");
+                            shostack();
+                        }
+#endif /* COMMENT */
+
+                    }
+                    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
+            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 */
+              case -6:                  /* Invalid command given w/no args */
+              case -2:                  /* Invalid command given w/args */
+#ifdef COMMENT
+#ifndef NOSPL
+                    /* This is going to be really ugly... */
+                    yy = mlook(mactab,atmbuf,nmac); /* Look in macro table */
+                    if (yy > -1) {                  /* If it's there */
+                        if (zz == -2) {             /* insert "do" */
+                            char *mp;
+                            mp = malloc((int)strlen(cmdbuf) + 5);
+                            if (!mp) {
+                                printf("?malloc error 1\n");
+                                return(-2);
+                            }
+                            sprintf(mp,"do %s ",cmdbuf); /* SAFE (checked) */
+                            ckstrncpy(cmdbuf,mp,CMDBL);
+                            free(mp);
+                            mp = NULL;
+                        } else {
+                            if (((int)strlen(atmbuf) + 5) < CMDBL)
+                              sprintf(cmdbuf,"do %s %c",atmbuf, CR); /* SAFE */
+                            else
+                              ckstrncpy(cmdbuf,"echo ?Too long\r",CMDBL);
+                        }
+                        if (ifcmd[cmdlvl] == 2) /* This one doesn't count! */
+                          ifcmd[cmdlvl]--;
+                        debug(F111,"stuff cmdbuf",cmdbuf,zz);
+                        repars = 1;     /* Go for reparse */
+                        continue;
+                    } else {
+                        char *p;
+                        int n;
+                        p = cmdbuf;
+                        lp = line;
+                        n = LINBUFSIZ;
+                        if (cmflgs == 0) printf("\n");
+                        if (zzstring(p,&lp,&n) > -1)
+                          printf("?Invalid: %s\n",line);
+                        else
+                          printf("?Invalid: %s\n",cmdbuf);
+                    } /* (fall thru...) */
+#else
+                    printf("?Invalid: %s\n",cmdbuf);
+#endif /* NOSPL */
+#else /* Not COMMENT */
+                    printf("?Invalid: %s\n",cmdbuf);
+#endif /* COMMENT */
+
+                case -9:                /* Bad, error message already done */
+                    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 */
+                      if (!quiet) {
+#ifdef COMMENT
+#ifndef NOSPL
+                          if (maclvl > -1)
+                            printf("Macro: %s; ",
+                                   m_arg[maclvl][0] ?
+                                   m_arg[maclvl][0] : "");
+#endif /* NOSPL */
+                          if (tlevel > -1)
+                            printf("Command file: %s, line %d\n",
+                                   tfnam[tlevel] ? tfnam[tlevel] : "",
+                                   tfline[tlevel]
+                                   );
+#else
+                          if (xcmdsrc > 0) {
+                              printf("Command stack:\n");
+                              shostack();
+                          }
+#endif /* COMMENT */
+                      }
+                      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
+freelocal(m) int m; {                   /* Free local variables */
+    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 *
+vardef(s,isarray,x1,x2) char * s; int * isarray, * x1, * x2; {
+    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
+addlocal(p) char * p; {
+    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
+dolocal() {                             /* Do the LOCAL command */
+    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
+dooutput(s, cx) char *s; int cx; {
+#ifdef SSHBUILTIN
+    extern int ssh_cas;
+    extern 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) {
+            printf("?Connection %s %s is not open.\n",
+                   network ? "to" : "on",
+                   ttname
+                   );
+            return(0);
+        }
+        if (ttvt(speed,flow) < 0) {
+            printf("?OUTPUT initialization error\n");
+            return(0);
+        }
+#endif /* NOLOCAL */
+    }
+#ifdef SSHBUILTIN
+    if ( network && nettype == NET_SSH && ssh_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;
+               int pause;
+               char * p, * b;
+               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 and initial prompt */
+
+VOID
+herald() {
+    int x = 0, i;
+    extern int srvcdmsg;
+    extern char * cdmsgfile[];
+#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 */
+
+#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 || bgset > 0 || (bgset != 0 && backgrd != 0)) x = 1;
+#else
+    x = 0;
+    if (noherald)
+      x = 1;
+    else if (bgset > 0)
+      x = 1;
+    else if (bgset < 0 && backgrd > 0)
+      x = 1;
+#endif /* COMMENT */
+
+    if (x == 0) {
+#ifdef datageneral
+        printf("%s, for%s\n",versio,ckxsys);
+#else
+#ifdef OSK
+        printf("%s, for%s\n",versio,ckxsys);
+#else
+        printf("%s, for%s\n\r",versio,ckxsys);
+#endif /* OSK */
+#endif /* datageneral */
+        printf(" Copyright (C) 1985, 2004,\n");
+        printf("  Trustees of Columbia University in the City of New York.\n");
+#ifdef OS2
+       shoreg();
+#endif /* OS2 */
+
+        if (!quiet && !backgrd) {
+#ifdef COMMENT
+/* "Default file-transfer mode is AUTOMATIC" is useless information... */
+            char * s;
+            extern int xfermode;
+#ifdef VMS
+            s = "AUTOMATIC";
+#else
+            if (xfermode == XMODE_A) {
+                s = "AUTOMATIC";
+            } else {
+                s = gfmode(binary,1);
+            }
+            if (!s) s = "";
+#endif /* VMS */
+            if (*s)
+              printf("Default file-transfer mode is %s\n", s);
+#endif /* COMMENT */
+
+            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 *
+gfmode(binary,upcase) int binary, upcase; {
+    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
+isaa(s) char * s; {                     /* Is associative array */
+    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
+mlook(table,cmd,n) struct mtab table[]; char *cmd; int n; {
+    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
+mxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
+    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) return(i);
+        if (w > 0) return(-1);
+#endif /* COMMENT */
+    }
+    return(-1);
+}
+
+/* mxxlook is like mxlook, but case-sensitive */
+
+int
+mxxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
+    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
+traceval(nam, val) char * nam, * val; { /* For TRACE command */
+    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
+addmmac(nam,s) char *nam, *s[]; {       /* Add a multiline macro definition */
+    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);
+}
+
+/* Here is the real addmac routine. */
+
+/* Returns -1 on failure, macro table index >= 0 on success. */
+
+int mtchanged = 0;
+
+int
+addmac(nam,def) char *nam, *def; {      /* Add a macro to the macro table */
+    int i, x, y, z, namlen, deflen, flag = 0;
+    int replacing = 0, deleting = 0;
+    char * p = NULL, c, *s;
+    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
+xdelmac(x) int x; {                     /* Delete a macro given its index */
+    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
+delmac(nam,exact) char *nam; int exact; { /* Delete the named macro */
+    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),0); /* 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 */
+                dclarray((char)(i+ARRAYBASE),0); /* (see pusharray()) */
+                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];
+        } 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];
+            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
+iseom(m) char * m; {                    /* Test if at end of macro def */
+    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
+doclslog(x) int x; {
+    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 *
+showstring(s) char * s; {
+    return(s ? s : "(null)");
+}
+
+char *
+showoff(x) int x; {
+    return(x ? "on" : "off");
+}
+
+char *
+showooa(x) int x; {
+    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
+shokeycode(c) int c;
+#endif
+/* shokeycode */ {
+    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
+shostrdef(s) CHAR * s; {
+    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 */
+#ifdef NEWFTP
+    printf(" %s\n",ckftpv);
+#endif /* NEWFTP */
+#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
+shotcs(csl,csr) int csl, csr; {         /* Show terminal character set */
+#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 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 ( 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 = "";
+
+    printf("Mouse settings:\n");
+    printf("   Button Count:   %d\n",mousebuttoncount());
+    printf("   Active:         %s\n\n",showoff(tt_mouse));
+
+    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:
+              printf("   %s = Character: %c \\%d\n",
+                     mousename(button,event),
+                     mousemap[button][event].key.scancode,
+                     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;
+#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[];
+#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: <ESC>%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",
+           (tt_cursor == 2) ? "full" :
+           (tt_cursor == 1) ? "half" : "underline",
+#ifdef CK_AUTODL
+           "autodownload",autodl == TAD_ON ?
+           (adl_err ? "on, error stop" : "on, error continue") : 
+           autodl == TAD_ASK ? 
+           (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: %-13f  %13s: %-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, col;
+        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, truereverse, trueunderline, trueitalic;
+        printf(
+    " Attribute:  blink: %-3s  reverse: %-3s  underline: %-3s italic: %-3s\n",
+                trueblink?"on":"off", truereverse?"on":"off",
+                trueunderline?"on":"off", trueitalic?"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 */
+
+#ifndef NOTRIGGER
+    printf(" %19s: %-13s\n","Trigger",
+           tt_trigger[0] ? tt_trigger[0] : "(none)");
+#endif /* NOTRIGGER */
+#ifdef UNIX
+#ifndef NOJC
+    printf(" %19s: %-13s\n\n","Suspend", showoff(xsuspend));
+#endif /* NOJC */
+#endif /* UNIX */
+
+    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 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 /* 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
+doshow(x) int x; {
+    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;
+
+#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 ((y = cmcfm()) < 0)
+        return(y);
+
+#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 */
+        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,"","\\F","()",3,0);
+            printf("\n");
+#ifndef NOHELP
+            printf(
+"HELP FUNCTION <name> 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);
+		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)";
+                  if (y < 10)
+                    printf(" \\%%%d = %s\n",y,s1);
+                  else
+                    printf(" \\&_[%d] = %s\n",y,s2);
+              }
+          } 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(" 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 ( 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;
+          printf("\n Exit warning %s\n", xitwarn ?
+                 (xitwarn == 1 ? "on" : "always") : "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;
+#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)");
+#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);
+#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 */
+
+#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 */
+
+#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\n", deblog ? debfil : "(none)");
+#endif /* DEBUG */
+#ifndef NOXFER
+          printf(" Packet log:      %s\n",   pktlog ? pktfil : "(none)");
+#endif /* NOXFER */
+#ifndef NOLOCAL
+          printf(" Session log:     %s\n",   seslog ? sesfil : "(none)");
+#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 */
+
+      case SHOIKS:
+        return(sho_iks());
+        break;
+
+#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:%d\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 */
+
+      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 */
+shomac(s1, s2) char *s1, *s2; {
+    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(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(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(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 long tokval;
+static char curtok;
+static long expval;
+
+#define LONGBITS (8*sizeof (long))
+#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 = atoi(s);
+        } else {
+            if (cmdlvl == 0 && !x_ifnum && !xerror)
+              printf("Bad number - \"%s\"\n",tbuf);
+            xerror = 1;
+            cp++;
+            return(gettok());
+        }
+        return(NUMBER);
+    }
+#endif /* COMMENT */
+}
+
+static long
+#ifdef CK_ANSIC
+expon(long x, long y)
+#else
+expon(x,y) long x,y;
+#endif /* CK_ANSIC */
+/* expon */ {
+    long 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() {
+    long 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 == '&') {
+        long 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 long
+#ifdef CK_ANSIC
+fact(long x)
+#else
+fact(x) long x;
+#endif /* CK_ANSIC */
+/* fact */ {                            /* factorial */
+    long result = 1;
+    while (x > 1)
+      result *= x--;
+    return(result);
+}
+
+/*
+ * term ::= factor termp
+ *
+ */
+static VOID
+term() {
+    factor();
+    termp();
+}
+
+static long
+#ifdef CK_ANSIC
+gcd(long x, long y)
+#else
+gcd(x,y) long 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 */
+            long 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((long) 1 << nshift);    /* else gcd is 1 */
+}
+
+/*
+ * exprp ::= NULL | {+,-,|,...} term exprp
+ *
+ */
+static VOID
+exprp() {
+    while (windex("+-|<>#@",curtok) != NULL) {
+        long 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 long
+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() */
+evalx(s) char *s; {
+    char * p;
+    int t;
+    t = x_ifnum;
+    x_ifnum = 1;
+    p = evala(s);
+    x_ifnum = t;
+    return(p);
+}
+
+char *
+evala(s) char *s; {
+    long 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 ? "" : ckltoa(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.
+  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.
+  -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;
+    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)
+          return(0);                    /* If dimension 0, just deallocate. */
+    }
+    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
+xarray(s) char * s; {
+    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;
+    s = buf+2;
+    if (*s == '&') {
+        buf[1] = CMDQ;
+        s--;
+    } else if (*s != CMDQ) {
+        buf[0] = CMDQ;
+        buf[1] = '&';
+        s = buf;
+    }
+    c = *(s+2);
+    if (isupper(c))
+      c = tolower(c);
+    if (c == '@')
+      c = 96;
+    x = (int)c - ARRAYBASE;
+    if (*(s+3) == '[')
+      *(s+3) = NUL;
+    return((x < 0 || x > 'z' - ARRAYBASE || *(s+3)) ? -1 : x);
+}
+
+/*  A R R A Y B O U N D S  --  Parse array segment notation \&a[n:m]  */
+
+/*
+  Call with s = array reference, 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
+arraybounds(s,lo,hi) char * s; int * lo, * hi; {
+    int i, x, y, range[2];
+    char buf[256], * p, * q;
+    char * tmp = NULL;
+
+    *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);
+    range[0] = -1;                      /* It's OK -- get contents */
+    range[1] = -1;                      /* of subscript brackets */
+    makestr(&tmp,s);                    /* Make a pokeable copy */
+    s = tmp;
+    p = s;
+    for (p = s, q = NULL; *p; p++) {    /* First find the brackets */
+        if (*p == '[') {
+            q = p+1;
+        } else if (*p == ']')
+          break;
+    }
+    if (q && *p == ']') {               /* If we have brackets... */
+        int quitnow = 0;
+        for (i = 0; i < 2 && !quitnow; i++) { /* Loop thru their contents */
+            for (p = q; *p; p++) {
+                if ((i == 0 && *p == ':') || *p == ']') {
+                    if (*p == ']')
+                      quitnow = 1;
+                    *p = NUL;
+                    if (*q) {           /* We have something */
+                        y = 255;        /* Expand variables, etc. */
+                        s = buf;
+                        zzstring(q,&s,&y);
+                        s = evalx(buf); /* Evaluate it arithmetically */
+                        if (s) if (*s)
+                          ckstrncpy(buf,s,256);
+                        if (!chknum(buf)) { /* Did we get a number? */
+                            makestr(&tmp,NULL); /* No, fail. */
+                            return(-1);
+                        }
+                        q = (i == 0) ? p+1 : NULL; /* Point to next if any */
+                        range[i] = atoi(buf); /* Set this one */
+                    }
+                    break;
+                }
+            }
+        }
+    }
+    makestr(&tmp,NULL);                 /* Free temporary poked string */
+    *lo = range[0];                     /* Return what we got */
+    *hi = range[1];
+    debug(F101,"arraybounds lo","",*lo);
+    debug(F101,"arraybounds hi","",*hi);
+    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
+arraynam(ss,c,n) char *ss; int *c; int *n; {
+    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;
+    zzstring(p,&sx,&y);                 /* Convert variables, etc. */
+    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);
+}
+
+int
+chkarray(a,i) int a, i; {               /* Check if array is declared */
+    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
+pusharray(x,z) int x, z; {
+    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
+parsevar(s,c,i) char *s; int *c, *i; {
+    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
+varval(s,v) char *s; int *v; {
+    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 = atoi(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 = atoi(p);                 /* success */
+    }
+    return(0);
+}
+
+/* Increment or decrement a variable */
+/* Returns -1 on failure, 0 on success */
+
+int
+incvar(s,x,z) char *s; int x; int z; {  /* Increment a numeric variable */
+    int 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,ckitoa(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
+dodo(x,s,flags) int x; char *s; int flags; {
+    int y;
+    extern int tra_asg, tra_cmd; int tra_tmp;
+#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;
+    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;
+
+/* Assign the new args one word per arg, allowing braces to group words */
+
+    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
+litcmd(src,dest,n) char **src, **dest; int n; {
+    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
+xwords(s,max,list,flag) char *s; int max; char *list[]; int flag; {
+    char *p;
+    int b, i, k, q, y, z;
+#ifndef NOSPL
+    int macro;
+    macro = (list == NULL);
+    debug(F010,"xwords",s,0);
+#endif /* NOSPL */
+
+#ifdef XWORDSDEBUG
+    printf("XWORDS string=%s\n",s);
+    printf("XWORDS max=%d\n",max);
+#endif /* XWORDSDEBUG */
+    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 (list)
+      for (i = 0; i <= max; i++)        /* Initialize pointers */
+        list[i] = NULL;
+
+    if (flag) max--;
+
+    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. */
+#ifdef XWORDSDEBUG
+                printf("1 z++ = %d\n", z);
+#endif /* XWORDSDEBUG */
+#ifndef NOSPL
+                if (macro) {            /* Doing macro args */
+                    if (z < 10) {
+                        varnam[1] = (char) (z + '0'); /* Assign last arg */
+                        addmac(varnam,p);
+                    }
+                    if (z <= max) {
+#ifdef COMMENT
+                        if (maclvl < 0)
+                          addmac(varnam,p);
+                        else
+#endif /* COMMENT */
+                          makestr(&(m_xarg[maclvl][z]),p);
+                    }
+                } else {                /* Not doing macro args */
+#endif /* NOSPL */
+                    list[z] = p;        /* Assign pointer. */
+#ifdef XWORDSDEBUG
+                    printf("[1]LIST[%d]=\"%s\"\n",z,list[z]);
+#endif /* XWORDSDEBUG */
+#ifndef NOSPL
+                }
+#endif /* NOSPL */
+                break;                  /* And get out. */
+            } else break;               /* Was not in a word */
+        }
+        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++;
+#ifdef XWORDSDEBUG
+                    printf("1 z++ = %d\n", z);
+#endif /* XWORDSDEBUG */
+                    list[z] = p;        /* Yes, point to it */
+#ifdef XWORDSDEBUG
+                    printf("[4]LIST[%d]=\"%s\"\n",z,list[z]);
+#endif /* XWORDSDEBUG */
+                    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 */
+#ifdef XWORDSDEBUG
+            printf("1 z++ = %d\n", z);
+#endif /* XWORDSDEBUG */
+
+#ifndef NOSPL
+            if (macro) {
+                if (z < 10) {
+                    varnam[1] = (char) (z + '0'); /* compute its name */
+                    addmac(varnam,p);   /* add it to the macro table */
+                }
+                if (z <= max) {
+#ifdef COMMENT
+                    if (maclvl < 0)
+                      addmac(varnam,p);
+                    else
+#endif /* COMMENT */
+                      makestr(&(m_xarg[maclvl][z]),p);
+                }
+            } else {
+#endif /* NOSPL */
+                list[z] = p;
+#ifdef XWORDSDEBUG
+                printf("[2]LIST[%d]=\"%s\"\n",z,list[z]);
+#endif /* XWORDSDEBUG */
+#ifndef NOSPL
+            }
+#endif /* NOSPL */
+            p = s+1;
+        }
+        s++;                            /* Point past this character */
+    }
+    if ((z == 0) && (y > 1)) {          /* Extra closing brace(s) at end */
+        z++;
+#ifndef NOSPL
+        if (macro) {
+            if (z < 10) {
+                varnam[1] = z + '0';    /* compute its name */
+                addmac(varnam,p);       /* Add rest of line to last arg */
+            }
+            if (z <= max) {
+#ifdef COMMENT
+                if (maclvl < 0)
+                  addmac(varnam,p);
+                else
+#endif /* COMMENT */
+                  makestr(&(m_xarg[maclvl][z]),p);
+            }
+        } else {
+#endif /* NOSPL */
+            list[z] = p;
+#ifdef XWORDSDEBUG
+            printf("[3]LIST[%d]=\"%s\"\n",z,list[z]);
+#endif /* XWORDSDEBUG */
+#ifndef NOSPL
+        }
+#endif /* NOSPL */
+    }
+#ifndef NOSPL
+    if (macro) {                        /* Macro */
+        if (maclvl < 0) {
+            a_dim[0] = z;               /* Array dimension is one less */
+            topargc = z + 1;            /* than \v(argc) */
+	    debug(F111,"a_dim[0]","D",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,"a_dim[0]","E",a_dim[0]);
+        }
+    }
+#endif /* NOSPL */
+    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
+doshift(n) int n; {                     /* n = shift count */
+    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
+docd(cx) int cx; {                      /* Do the CD command */
+    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
+prtopt(lines,s) int * lines; char *s; { /* Print an option */
+    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 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 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 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 /* IFDEBUG */
+#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 */
+
+    sprintf(line,"CKMAXPATH=%d",CKMAXPATH); /* SAFE */
+    makestr(&(optlist[noptlist++]),line);
+
+    sprintf(line,"CKMAXOPEN=%d",CKMAXOPEN); /* SAFE */
+    makestr(&(optlist[noptlist++]),line);
+
+    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 */
+
+#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 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 */
+#endif /* VMS */
+#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 */
+#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_BAUDBOY
+    makestr(&(optlist[noptlist++]),"HAVE_BAUDBOY");
+#endif /* HAVE_BAUDBOY */
+#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 /* NOSETBUF */
+#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 NOSETREU
+    makestr(&(optlist[noptlist++]),"NOSETREU");
+#endif /* NOSETREU */
+#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 __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 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 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 OS2ORUNIX
+    makestr(&(optlist[noptlist++]),"OS2ORUNIX");
+#endif /* OS2ORUNIX */
+#ifdef VMSORUNIX
+    makestr(&(optlist[noptlist++]),"VMSORUNIX");
+#endif /* VMSORUNIX */
+#ifdef VMS64BIT
+    makestr(&(optlist[noptlist++]),"VMS64BIT");	/* VMS on Alpha or IA64 */
+#endif /* VMS64BIT */
+#ifdef VMSI64
+    makestr(&(optlist[noptlist++]),"VMSI64"); /* VMS on IA64 */
+#endif /* VMSI64 */
+#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 */
+#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++]),"MACOSX103");
+#endif
+
+#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 i286
+    makestr(&(optlist[noptlist++]),"i286");
+#endif
+#ifdef M_I286
+    makestr(&(optlist[noptlist++]),"M_I286");
+#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 __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 __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 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 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 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 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 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");
+#endif /* CK_SSL */
+
+    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);
+    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 */
+    UNKNOWN WINDOWS PLATFORM
+#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 */
+    printf("\n");
+    if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+    printf("Major optional features included:\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 (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 */
+
+    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; }
+
+#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 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 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 /* 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 NOHTTP
+    printf(" No built-in HTTP client\n");
+    if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+#endif /* NOHTTP */
+
+#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 UNIX
+#ifndef NETPTY
+    printf(" No pseudoterminal control\n");
+    if (++lines > cmd_rows - 3) { if (!askmore()) return(1); else lines = 0; }
+    flag = 1;
+#endif /* NETPTY */
+#endif /* UNIX */
+
+#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 NT
+#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 /* NT */
+#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 */
+
+    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 __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 /* __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
+             );
+    if (!prtopt(&lines,line)) return(0);
+    if (!prtopt(&lines,"")) return(0);  /* Start a new section */
+    sprintf(line,"sizeofs: int=%ld",sizeof(int)); /* SAFE */
+    if (!prtopt(&lines,line)) return(0);
+    sprintf(line,"long=%ld",sizeof(long)); /* SAFE */
+    if (!prtopt(&lines,line)) return(0);
+    sprintf(line,"short=%ld",sizeof(short)); /* SAFE */
+    if (!prtopt(&lines,line)) return(0);
+    sprintf(line,"char=%ld",sizeof(char)); /* SAFE */
+    if (!prtopt(&lines,line)) return(0);
+    sprintf(line,"char*=%ld",sizeof(char *)); /* SAFE */
+    if (!prtopt(&lines,line)) return(0);
+#ifdef LONG_MAX
+    sprintf(line,"LONG_MAX=%d",LONG_MAX); /* SAFE */
+#endif /* LONG_MAX */
+#ifdef CKFLOAT
+    sprintf(line,"float=%ld",sizeof(float)); /* SAFE */
+    if (!prtopt(&lines,line)) return(0);
+    sprintf(line,"double=%ld",sizeof(double)); /* 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 */
+#endif /* CKFLOAT */
+
+    prtopt(&lines,"");
+    return(0);
+}
+#endif /* NOSHOW */
+#endif /* NOICP */
diff --git a/ckermit-8.0.211/ckuus6.c b/ckermit-8.0.211/ckuus6.c
new file mode 100644
index 0000000..5dcd828
--- /dev/null
+++ b/ckermit-8.0.211/ckuus6.c
@@ -0,0 +1,10878 @@
+#include "ckcsym.h"
+#ifndef NOICP
+
+/*  C K U U S 6 --  "User Interface" for Unix Kermit (Part 6)  */
+
+/*
+  Authors:
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    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"
+#include "ckcxla.h"
+#include "ckcnet.h"                     /* Network symbols */
+#include <signal.h>
+
+#ifdef VMS
+#ifndef TCPSOCKET
+#include <errno.h>
+#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;
+
+#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 int vmode;
+extern int k95stdout;
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO                        /* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else
+#define APIRET ULONG
+#include <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#endif /* NT */
+#include "ckocon.h"
+#endif /* OS2 */
+
+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;
+
+#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;
+
+#ifndef NOSPL
+int askflag = 0;                        /* ASK-class command active */
+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 */
+
+extern int zchkod, zchkid;
+
+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);
+
+struct keytab copytab[] = {
+    { "/append",      998,      0 },
+#ifndef NOSPL
+    { "/fromb64",     997,      0 },
+#endif /* NOSPL */
+    { "/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 },
+    { "/swap-bytes",  999,      0 },
+#ifndef NOSPL
+    { "/tob64",       996,      0 },
+#endif /* NOSPL */
+    { "/verbose",     DEL_VRB,  CM_INV }
+};
+int ncopytab = sizeof(copytab)/sizeof(struct keytab);
+
+#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 */
+
+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 },
+    { "c-kermit",   XXIFCK, 0 },
+    { "command",    XXIFCM, 0 },
+    { "count",      XXIFCO, 0 },
+    { "dcl",        XXIFDC, CM_INV },
+    { "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 },
+#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, 0 },
+    { "kbhit",      XXIFKB, 0 },
+#ifdef UNIX
+    { "kerbang",    XXIFKG, 0 },
+#else
+    { "kerbang",    XXIFKG, CM_INV },
+#endif /* UNIX */
+    { "lgt",        XXIFLG, 0 },
+    { "llt",        XXIFLL, 0 },
+    { "local",      XXIFLO, 0 },
+    { "match",      XXIFMA, 0 },
+    { "ms-kermit",  XXIFMS, CM_INV },
+#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 */
+    { "true",       XXIFTR, 0 },
+    { "version",    XXIFVE, 0 },
+    { "wild",       XXIFWI, 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 */
+
+#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) );
+_PROTOTYP(static int dncvt, (int, int, int, int) );
+_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 */
+#ifdef DCMDBUF
+extern int
+ *ifcmd,  *count,  *iftest, *intime,
+ *inpcas, *takerr, *merror, *xquiet;
+#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[];
+#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
+
+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;
+
+int
+doask(cx) int cx; {
+    extern int cmflgs, asktimer, timelimit;
+#ifdef CK_RECALL
+    extern int on_recall;
+#endif /* CK_RECALL */
+    int popupflg = 0;
+    int guiflg = 0;
+    int nomsg = 0;
+    int mytimer = 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 */
+
+    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 */
+               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 */
+               _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;
+		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_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 != XXGOK && cx != XXRDBL) { /* 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, or GETC */
+
+    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. */
+    } else {                            /* For others, regular echoing. */
+        cmini(ckxech);
+    }
+    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 */
+        {
+            debug(F101,"GETC conchk","",conchk());
+            x = coninc(timelimit);      /* Just 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;
+#endif /* CK_RECALL */
+        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
+doincr(cx) int cx; {                    /* INCREMENT, DECREMENT */
+    char vnambuf[VNAML+1];              /* Buffer for variable names */
+    int eval = 0;
+    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 = cmnum("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
+xxundef(s,verbose,simulate) char * s; int verbose, simulate; {
+    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
+doundef(cx) int cx; {                   /* UNDEF, _UNDEF */
+    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
+dodef(cx) int cx; {
+    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 */
+getdname() {
+    return(d_name ? d_name : "");
+}
+
+char *
+getdnum(n) int n; {                     /* Get dial number n from directory */
+    if (n < 0 || n > dncount || n > MAXDNUMS)
+      return("");
+    else
+      return(dn_p[n]);
+}
+
+char *                  /* Check area code for spurious leading digit */
+chk_ac(i,buf) int i; char buf[]; {
+    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
+callisld(src, dest) char * src, * dest; {
+    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 *
+xdial(s) char *s; {                     /* Run dial string thru macro */
+    int x, m;
+    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,s,0);                    /* Set up the macro */
+    if (x > 0) {
+        while (maclvl > m)              /* Execute the parser */
+          parser(1);
+        return(mrval[maclvl+1]);        /* Return the result */
+    }
+    return(NULL);
+}
+#endif /* NOSPL */
+
+static int
+dncvt(k,cx, prefix, suffix)
+    int k, cx, prefix, suffix; {        /* Dial Number Convert */
+    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
+ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
+    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 (wierd) name. */
+        goto ddexit;
+    }
+#endif /* VMS */
+    debug(F110,"ddcvt s2 (old)",s2,0);
+    if ((f = fopen(s2,"r")) == NULL) {  /* Reopen old file with wierd 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, i, 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 *
+pncvt(s) char *s; {                     /* Phone number conversion */
+    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
+dodial(cx) int cx; {                    /* DIAL or REDIAL */
+    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;
+
+    debug(F101,"dodial cx","",cx);
+    debug(F111,"dodial diallcc",diallcc,diallcc);
+
+    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;
+#ifndef NOSPL
+                char * p;
+#endif /* NOSPL */
+                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) 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");
+                if (dialmac)
+                  printf(" Number: \"%s\" => \"%s\"\n",sav,s);
+                else
+                  printf(" Number: \"%s\"\n",s);
+                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
+typeline(buf,len,outcs,ofp) char * buf; int len, outcs; FILE * ofp; {
+    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 */
+typegetline(incs, outcs, buf, n) int incs, outcs, n; char * buf; {
+    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, <CR><LF> is returned as <LF>. */
+/* 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] == 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 */
+    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 */
+
+int
+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;
+/* dotype */ {
+    extern long 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, c, 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
+    int gui = 0;
+#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;
+    }
+    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;
+    }
+
+#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 = 0L;
+        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(F011,"dotype line",buf,len);
+#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
+        if ( gui ) {
+            int i;
+            unsigned short * uch = (unsigned short *)buf;
+            for ( i=0; i<len/2; i++)
+                gui_text_popup_append(uch[i]);
+			gui_text_popup_append(CR);
+			gui_text_popup_append(LF);
+        } 
+        else
+#endif /* KUI */
+        typeline(buf,len,outcs,ofp);    /* Print line, length based */
+#ifdef CK_TTGWSIZ
+        debug(F101,"dotype n","",n);
+        if (paging > 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
+    if ( gui )
+        gui_text_popup_wait(-1);        /* Wait for user to close the dialog */
+#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: */
+
+static struct keytab greptab[] = {
+    { "/count",        GREP_COUN, CM_ARG },
+    { "/dotfiles",     GREP_DOTF, 0 },
+    { "/linenumbers",  GREP_NUMS, 0 },
+    { "/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 */
+    { "/type",         GREP_TYPE, CM_ARG },
+    { "", 0, 0 }
+};
+static int ngreptab =  sizeof(greptab)/sizeof(struct keytab)-1;
+
+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;
+    char c, name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p, *s, *cv = NULL;
+    FILE * fp = NULL;
+
+    int                                 /* Switch values and defaults */
+      gr_coun = 0,
+      gr_name = 0,
+      gr_nobk = 0,
+      gr_case = 1,
+      gr_noli = 0,
+      gr_noma = 0,
+      gr_nums = 0,
+      gr_page = xaskmore;
+
+    struct FDB sw, fl;
+
+    g_matchdot = matchdot;              /* Save global matchdot setting */
+    outfile[0] = NUL;
+
+    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,			/* 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);
+        }
+        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;
+#ifdef RECURSIVE
+          case GREP_RECU:
+            recursive = 1;
+            break;
+#endif /* RECURSIVE */
+          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;
+        }
+    }
+    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 */
+#else
+    {
+        int flags = ZX_FILONLY;         /* Expand file list */
+        if (matchdot)  flags |= ZX_MATCHDOT;
+        if (recursive) flags |= ZX_RECURSE;
+        fc = nzxpand(line,flags);
+    }
+#endif /* ZXREWIND */
+#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);
+
+    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 */
+        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[LINBUFSIZ] = NUL;      /* Make sure it's terminated */
+	    debug(F111,"GREP",line,fline);
+            len = (int)strlen(line);    /* Get length */
+            while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
+              line[--len] = NUL;        /* Chop off terminators */
+            match = ckmatch(p,line,gr_case,1+4); /* Match against pattern */
+            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 */
+                if (gr_name) {          /* Don't care how many lines match */
+                    fclose(fp);         /* Close the file */
+                    fp = NULL;          /* and quit the line-reading loop. */
+                    break;
+                }
+                if (gr_coun || gr_noli) /* Not listing each line */
+                  continue;             /* so don't print anything now. */
+                if (wild) {		/* If searching multiple files */
+                    fprintf(ofp,"%s:",name); /* print filename. */
+                    len += (int)strlen(name) + 1;
+                }
+                if (gr_nums) {          /* If line numbers wanted */
+                    char nbuf[32];
+                    len += ckmakmsg(nbuf,32,ckitoa(fline),":",NULL,NULL);
+                    fprintf(ofp,"%s",nbuf);
+                }
+                if (cmd_rows > 0 && cmd_cols > 0)
+                  sline += (len / cmd_cols) + 1;
+                fprintf(ofp,"%s\n",line); /* Print the line. */
+                if (sline > cmd_rows - 3) {
+                    if (!askmore()) goto xgrep; else sline = 0;
+                }
+            }
+        }
+        if (!gr_noli) {			/* If not not listing... */
+            x = 0;
+            if (gr_coun) {              /* Show match count only */
+                fprintf(ofp,"%s:%d\n",name,count);
+                x++;
+            } else if (gr_name && count > 0) { /* Show name only */
+                fprintf(ofp,"%s\n",name);
+                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_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);
+}
+
+/* System-independent directory */
+
+static char ** dirlist = NULL;
+static int ndirlist = 0;
+
+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 },
+    { "/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 },
+    { "/heading",     DIR_HDG, 0 },
+    { "/isodate",     DIR_ISO, 0 },
+    { "/larger-than", DIR_LAR, CM_ARG },
+#ifdef CKSYMLINK
+    { "/followlinks", DIR_LNK, 0 },
+#endif /* CKSYMLINK */
+    { "/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 },
+    { "/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 },
+    { "/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 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
+domydir() {                             /* Internal DIRECTORY command */
+    extern char *months[];
+#ifdef VMS
+    _PROTOTYP( char * zrelname, (char *,char *) );
+    char * cdp = NULL;
+#endif /* VMS */
+
+    char name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p = NULL, c = NUL;
+    char linebuf[CKMAXPATH+256];
+    char * mstr = NULL, * dstr = NULL, * s2 = NULL;
+    long len = 0, ndirs = 0, nfiles = 0, nbytes = 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 fs = 0;
+    int multiple = 0;
+    int cmifn1 = 1, cmifn2 = 0;
+    long minsize = -1L, maxsize = -1L;
+    struct FDB sw, fi, fl;
+    char dbuf[32], xbuf[32];
+
+#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];
+
+    g_matchdot = matchdot;              /* Save global matchdot setting */
+    nolinks = 2;                        /* (it should already be 2) */
+    outfile[0] = NUL;                   /* No output file yet */
+
+    if (ofp != stdout) {                /* In case of previous interruption */
+        if (ofp) fclose(ofp);
+        ofp = stdout;
+    }
+    for (i = 0; i < 16; i++) xlist[i] = NULL;
+
+    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;
+
+#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 */
+
+    diractive = 1;
+    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 */
+           ndirswtab,                   /* addtl numeric data 1: tbl size */
+           4,                           /* addtl numeric data 2: 4 = cmswi */
+           xxstring,                    /* Processing function */
+           dirswtab,                    /* Keyword table */
+           &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);
+        }
+        if (!getval && (cmgkwflgs() & CM_ARG)) {
+            printf("?This switch requires an argument\n");
+            return(-9);
+        }
+        switch (k = cmresult.nresult) {
+          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 */
+            nolinks = 0;
+            cmifn1 &= ~(2);
+            goto again;
+          case DIR_NLK:                 /* Don't follow links */
+            nolinks = 2;
+            cmifn1 &= ~(2);
+            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:
+            if (!getval) break;
+            if ((x = cmnum("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;
+
+#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;
+
+          default:
+            printf("?Sorry, not implemented yet - \"%s\"\n", atmbuf);
+            goto xdomydir;
+        }
+    }
+    ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of filespec */
+
+/* ^^^ START MULTIPLE */
+    
+    while (1) {
+	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 */
+
+    s = line;
+
+    if ((x = cmcfm()) < 0)              /* Get confirmation */
+      return(x);
+    if (cmresult.fcode != _CMIFI) {     /* Nothing matched */
+        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;
+    }
+    wild = cmresult.nresult;            /* Wildcard was given? */
+    debug(F111,"domydir cmifi2",s,wild);
+
+    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);
+        }
+        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 */
+	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);
+#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;
+        }
+        array = xx;
+        ap = a_ptr[array];
+        if (n < 1) {
+            rc = 0;
+            goto xdomydir;
+        }
+    } else
+#endif /* NOSPL */
+      if (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",
+                     s
+                     );
+          rc = -9;
+          goto xdomydir;
+    }
+    nx = x;                             /* Remember how many files */
+
+    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 (!verbose) {                     /* /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 = filhelp(x,"","",n,0);
+            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 = nbytes = 0L;       /* Initialize counters */
+
+    if (dir_exc)                        /* Have exception list? */
+      makelist(dir_exc,xlist,16);	/* Yes, convert to array */
+
+    diractive = 1;
+    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 zgetfs",name,len);
+#ifdef VMSORUNIX
+        itsadir = zgfs_dir;             /* See if it's a directory */
+#else
+        itsadir = (len == -2 || isdir(name));
+#endif /* VMSOUNIX */
+        debug(F111,"domydir itsadir",name,itsadir);
+        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;
+        }
+        if (summary) {                  /* Summary only, no detail */
+            znext(name);
+            continue;
+        }
+#ifndef NOSPL
+        if (array) {
+            debug(F111,"domydir array",name,nfiles);
+            if (ap)
+              makestr(&(ap[nmatches]),name);
+            znext(name);
+            continue;
+        }
+#endif /* NOSPL */
+
+/*
+  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.
+*/
+        dstr = zfcdat(name);            /* Get modification date/time */
+        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 < 0) {       /* Directory */
+#ifdef VMS
+            sprintf(linebuf,"%-22s%-10s  %s  %s",p,"<DIR>",dstr,name);
+#else
+            if (p)
+              sprintf(linebuf,"%10s%-10s  %s  %s",p,"<DIR>",dstr,name);
+            else
+              sprintf(linebuf,"%-10s  %s  %s", "<DIR>", dstr, name);
+#endif /* VMS */
+        } else {                        /* Regular file */
+#ifdef VMS
+            sprintf(linebuf,"%-22s%10ld  %s  %s", p, len, dstr, name);
+#else
+            if (p)
+              sprintf(linebuf,"%10s%10ld  %s  %s", p, len, dstr, name);
+            else
+              sprintf(linebuf,"%10ld  %s  %s", len, dstr, name);
+#endif /* VMS */
+        }
+#ifdef UNIX
+#ifdef CKSYMLINK
+        if (zgfs_link) {
+            int n, m;
+            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 i, 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) {
+            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 */
+            }
+        }
+    }
+#ifndef NOSPL
+    if (array) {
+        if (ap)
+          makestr(&(ap[0]),ckitoa(nmatches));
+        rc = 1;
+        goto xdomydir;
+    }
+#endif /* NOSPL */
+    if (xsort) {
+        skey = 0;
+#ifdef VMS
+        switch (sortby) {
+          case DIRS_NM: skey = dlen + 35; break;
+          case DIRS_DT: skey = 33; break;
+          case DIRS_SZ: skey = 21;
+        }
+#else
+        if (p) {
+            switch (sortby) {
+              case DIRS_NM: skey = dlen + 24; break;
+              case DIRS_DT: skey = 22; break;
+              case DIRS_SZ: skey = 10;
+            }
+        } else {
+            switch (sortby) {
+              case DIRS_NM: skey = dlen + 14; break;
+              case DIRS_DT: skey = 12; break;
+              case DIRS_SZ: skey = 0;
+            }
+        }
+#endif /* VMS */
+        sh_sort(dirlist,NULL,ndirlist,skey,reverse,filecase);
+        for (i = 0; i < ndirlist; i++) {
+            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 */
+            }
+        }
+    }
+
+    if (heading || summary) {
+#ifdef CKFLOAT
+        CKFLOAT gm;
+#endif /* CKFLOAT */
+        fprintf(ofp,"\n%ld director%s, %ld file%s, %ld byte%s",
+               ndirs,
+               (ndirs == 1) ? "y" : "ies",
+               nfiles,
+               (nfiles == 1) ? "" : "s",
+               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");
+    }
+  xdomydir:
+    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
+dodir(cx) int cx; {                     /* Do the DIRECTORY command */
+    char *dc , *msg;
+
+#ifdef OS2
+    return(domydir());
+#else /* OS2 */
+    if (nopush
+#ifdef DOMYDIR                          /* Builds that domydir() by default */
+        || (cx == XXDIR || cx == XXLDIR)
+#endif /* DOMYDIR */
+        )
+      return(domydir());                /* 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
+doenable(y,x) int y, x; {
+#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, j, k, x;
+    int fs = 0;                         /* Need to call fileselect() */
+    int len = 0;
+    int bad = 0;
+    int getval = 0, asking = 0;
+    int simulate = 0, rc = 0;
+    long 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",atmbuf);
+            else if ((x = zchki(atmbuf)) == -1)
+	      printf("?File not found: %s\n",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) {
+            int i;
+#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);
+#ifdef 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;
+
+    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 */
+
+    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,"FOR 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 fy","",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,"FOR B",line,0);
+#endif /* DEBUG */
+
+    x_ifnum = 1;                        /* Increment or parenthesis */
+    di = (fx < fy) ? "1" : "-1";        /* Default increment */
+    if ((y = cmnum("increment",di,10,&fz,xxstring)) < 0) {
+        debug(F111,"dofor increment",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);
+    } else {                            /* Number */
+        x_ifnum = 0;
+        debug(F101,"dofor fz","",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,"FOR C",line,0);
+#endif /* DEBUG */
+
+    /* Insert the appropriate comparison operator */
+    if (fz < 0)
+      *lp++ = '<';
+    else
+      *lp++ = '>';
+    *lp++ = SP;
+
+#ifdef DEBUG
+    *lp = NUL;
+    debug(F110,"FOR 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 to execute","",&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);
+    }
+#ifdef DEBUG
+    *lp = NUL;
+    debug(F110,"FOR E",line,0);
+#endif /* DEBUG */
+
+#ifdef COMMENT
+/* Too strict */
+    if (fz == 0) {
+        printf("?Zero increment not allowed\n");
+        return(0);
+    }
+#endif /* COMMENT */
+/*
+  In version 8.0 we decided to allow macro names anyplace 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.
+*/
+    if (mustquote) {                    /* \%i-style loop variable */
+        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);
+            }
+        }
+    } else {                            /* Loop variable is a macro */
+        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(F010,"FOR command",line,0);   /* Execute the FOR macro. */
+    return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC));
+
+badfor:
+    printf("?Incomplete FOR command\n");
+    return(-2);
+}
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+/* Do the BUG command */
+
+int
+dobug() {
+    int n;
+    char * s = "";
+    extern char * k_info_dir;
+
+    if (k_info_dir)
+      s = k_info_dir;
+
+#ifdef COMMENT
+    printf("\n%s,%s\n Numeric: %ld",versio,ckxsys,vernum);
+#endif /* COMMENT */
+    printf(
+"\nBefore requesting technical support from Columbia U., please consult:\n\n"
+           );
+    n = 7;
+#ifdef OS2
+    printf(" . Your \"Kermit 95\" user manual (use the MANUAL command).\n");
+    printf(" . The technical reference manual, \"Using C-Kermit\".\n");
+    n += 2;
+#else
+    printf(" . The book \"Using C-Kermit\" (type HELP for more info).\n");
+    n += 1;
+#endif /* OS2 */
+
+    printf(" . Your own organization's support staff, if any.\n");
+    printf(
+" . The comp.protocols.kermit.misc newsgroup.\n");
+    printf(
+" . The Kermit support website, http://www.columbia.edu/kermit/support.html \n"
+           );
+    printf(
+
+" . The Kermit FAQ, http://www.columbia.edu/kermit/newfaq.html \n");
+#ifdef OS2
+    printf(
+" . The Kermit 95 FAQ, http://www.columbia.edu/kermit/k95faq.html \n");
+    n++;
+#endif /* OS2 */
+
+    printf(
+" . The C-Kermit FAQ, http://www.columbia.edu/kermit/ckfaq.html \n");
+    n += 4;
+    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+    printf("\n\
+If you still need help or have a bug to report after consulting these sources,"
+           );
+    printf("\nsend e-mail to:\n\n");
+    n += 2;
+    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+    printf("  mailto:kermit-support@columbia.edu\n\n");
+    n += 1;
+    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+    printf("Or contact us by post:\n\n");
+    printf(
+"  Kermit, Columbia University, 612 W 115 Street, New York NY  10025, USA\n\n"
+           );
+    n += 1;
+    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+    printf("Or by fax at +1 (212) 662-6442.\n\n");
+    n += 1;
+    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#ifdef COMMENT
+    printf("Telephone support is available too:\n\n");
+    n += 1;
+    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+    printf(
+    "  +1 (212) 854-5126, from anywhere, $25.00 USD per call, MC/Visa\n\n");
+    n += 1;
+    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* COMMENT */
+#ifndef NOSHOW
+#ifndef NOFRILLS
+    printf(
+"Before reporting problems, please use the SHOW FEATURES command\n");
+    if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+    printf(
+"to get detailed program version and configuration information.\n\n");
+#endif /* NOFRILLS */
+#endif /* NOSHOW */
+    return(1);
+}
+#endif /* NOFRILLS */
+
+#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
+tod2sec(t) char * t; {
+    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
+dopaus(cx) int cx; {
+    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 i, 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 i, x, listing = 0, nolist = 0, havename = 0;
+    struct FDB sw, fi;
+    int targetisdir = 0;
+    int targetlen = 0;
+    int swapping = 0;
+    int appending = 0;
+    int fromb64 = 0;
+    int tob64 = 0;
+    int wild = 0;
+    int rc = 1;
+
+    cmfdbi(&sw,                         /* 2nd FDB - optional /PAGE switch */
+           _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,                         /* 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 */
+        if (x < 0)                      /* Error */
+          return(x);
+        switch (cmresult.fcode) {
+          case _CMKEY:
+            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;
+#ifndef NOSPL
+              case 997:
+                fromb64 = 1;
+                break;
+              case 996:
+                tob64 = 1;
+                break;
+#endif /* NOSPL */
+            }
+            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 */
+    if ((x = cmofi("destination name and/or directory",
+#ifdef UNIX
+                   "."
+#else
+                   ""
+#endif /* UNIX */
+                   ,&s,xxstring)) < 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 *.* bifile" 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 */
+    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);
+
+#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 (listing) printf("%s => %s ",line,p);
+
+        /* Straight copy */
+        if (!swapping && !appending && !fromb64 && !tob64) {
+            debug(F110,"COPY zcopy",line,0);
+
+            if ((x = zcopy(line,p)) < 0) { /* Let zcopy() do it. */
+                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 {
+                if (listing) 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 ((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 (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 ((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 ((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;
+                    }
+                }
+            }
+            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 NORENAME
+#ifndef NOFRILLS
+#ifdef ZRENAME
+int
+dorenam() {
+    /* Parse a file or a directory name */
+    int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
+    int nolist = 0;
+    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:
+		nolist = 1;
+                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 (zrename(line,p) < 0) {
+            if (listing)
+	      printf("(FAILED: %s)\n",ck_errstr());
+	    else if (!nolist)
+	      printf("?%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,"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 */
+
+/*
+  Note: COPY, RENAME, DELETE and similar commands should have options to
+  stop or proceed when they are operating on multiple files and the operation
+  fails.
+*/
+    while (z-- > 0) {
+        if (!(z == 0 && !wild))
+          znext(line);
+        if (!line[0])
+          break;
+        if (listing) printf("%s => %s ",line,p);
+        if (zrename(line,p) < 0) {
+            if (listing)
+	      printf("(FAILED: %s)\n",ck_errstr());
+	    else if (!nolist)
+	      printf("?%s - %s\n",ck_errstr(),line);
+            rc = 0;
+        } else {
+            if (listing) printf("(OK)\n");
+        }
+    }
+#ifdef VMS
+    concb((char)escape);
+#endif /* VMS */
+    return(success = rc);
+}
+#endif /* ZRENAME */
+#endif /* NOFRILLS */
+#endif /* NORENAME */
+
+#ifndef NOSPL
+
+/* Do the RETURN command */
+
+int
+doreturn(s) char *s; {
+    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
+doxget(cx) int cx; {
+    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 long 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 {                  /* Temporary array for switch values */
+        char * sval;
+        int ival;
+    } pv[SND_MAX+1];
+    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()))
+          return(doftpget(cx,0));
+    }
+#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;
+    }
+    /* 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 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 */
+             ,
+           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 ((x = cmfld("Name to store it under","",&s,NULL)) < 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 = 1L;
+#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;
+        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 XIF, 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
+dogta(cx) int cx; {
+    int i, n;
+    char c, *p,  mbuf[4];
+    extern int topargc, cmdint;
+    extern char ** topxarg;
+
+    if ((y = cmcfm()) < 0)
+      return(y);
+    debug(F101,"dogta cx","",cx);
+    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 */
+            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];
+        } 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 */
+        if (maclvl == 1) {
+            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 {
+            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.
+*/
+#ifdef BIGBUFOK
+#define LBLMAXLEN 255                   /* Max label length */
+#else
+#define LBLMAXLEN 63
+#endif /* BIGBUFOK */
+
+int
+dogoto(s, cx) char *s; int cx; {
+    int i, j, x, y, z, bc;
+    int empty = 0, stopflg = 0;
+    char * cmd;                         /* Name of this command */
+    char tmplbl[LBLMAXLEN+1], *lp;      /* Current label from command stream */
+    char tmp2[LBLMAXLEN+1];             /* SWITCH label conversion buffer */
+    char tmp3[LBLMAXLEN+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);
+    ckstrncpy(tmp3+1,s,LBLMAXLEN-1);
+    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);
+            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) - y + 1;
+            debug(F010,"GOTO in macro",lp,0);
+
+            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++ > LBLMAXLEN) /* j = length of word from macro */
+                      break;
+#ifdef COMMENT
+                    if (*tp < 33 || *tp == ',') /* Look for end of word */
+#else
+                    if (!*tp || *tp == ',')     /* Look for end of word */
+#endif /* COMMENT */
+                      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 = LBLMAXLEN - 1;
+                    char * p = tmp2;
+                    zzstring(tmplbl,&p,&n);
+                    ckstrncpy(tmplbl,tmp2,LBLMAXLEN);
+                    tmp2[49] = NUL;
+                }
+                debug(F111,"GOTO s",s,y);
+                debug(F111,"GOTO tmplbl",tmplbl,j);
+                debug(F101,"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
+chkvar(s) char *s; {
+    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
+boolexp(cx) int cx; {
+    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 */
+
+    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? */
+#ifdef FNFLOAT
+      case _CMFLD:                      /* A "field" */
+        if (isfloat(cmresult.sresult,0)) { /* A floating-point number? */
+            f1 = floatval;              /* Yes, get its value */
+            f1flag = 1;                 /* remember we did this */
+            ifc = 9999;                 /* Set special "if-code" */
+        } else
+          return(-2);
+#endif /* FNFLOAT */
+      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 */
+        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);
+        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 XXIFLG:                      /* If Lexically Greater Than */
+        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);
+        }
+        tp = lp + x + 2;                /* tp points to second string */
+        strcpy(tp,s);                   /* safe (checked) */
+        x = ckstrcmp(lp,tp,-1,inpcas[cmdlvl]); /* Use longest length */
+        switch (ifc) {
+          case XXIFEQ:                  /* IF EQUAL (string comparison) */
+            z = (x == 0);
+            break;
+          case XXIFLL:                  /* IF Lexically Less Than */
+            z = (x < 0);
+            break;
+          case XXIFLG:                  /* If Lexically Greater Than */
+            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 >  */
+
+        /* Really should use longs here... */
+        /* But cmnum parses ints. */
+        int xx, n1 = 0, n2 = 0;
+        if (ifc == XXIFVE) {
+            n1 = (int) 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 = count[cmdlvl];
+            } else if (!ckstrcmp(lp,"version",7,0)) {
+                n1 = (int) vernum;
+            } else if (!ckstrcmp(lp,"argc",4,0)) {
+                n1 = (int) 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 = atoi(lp);
+                  } else {              /* Check for arithmetic expression */
+                      q = evala(lp);    /* cmnum() does this but ... */
+                      if (chknum(q))    /* we're not using cmnum(). */
+                        n1 = atoi(q);
+                      else
+                        return(-2);
+                  }
+            }
+        }
+        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 = count[cmdlvl];
+        } else if (!ckstrcmp(tp,"version",7,0)) {
+            n2 = (int) vernum;
+        } else if (!ckstrcmp(tp,"argc",4,0)) {
+            n2 = (int) macargc[maclvl];
+        } else {
+#ifdef FNFLOAT
+            if (isfloat(tp,0) > 1) {
+                f2 = floatval;
+                f2flag = 1;
+            } else
+#endif /* FNFLOAT */
+            if (chknum(tp)) {
+                n2 = atoi(tp);
+            } else {
+                q = evala(tp);
+                if (chknum(q))
+                  n2 = atoi(q);
+                else
+                  return(-2);
+            }
+        }
+        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;
+          z = (xcmdsrc == 0) ? 0 : cfilef;
+          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
+doif(cx) int cx; {
+    int x, y, z; char *s, *p;
+    char *q;
+#ifdef OS2
+    extern int keymac;
+#endif /* OS2 */
+
+    debug(F101,"doif cx","",cx);
+
+    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(F101,"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. */
+                  if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
+                      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(F010,"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
+dotake(s) char *s; {
+#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 {
+        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;
+        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 */
diff --git a/ckermit-8.0.211/ckuus7.c b/ckermit-8.0.211/ckuus7.c
new file mode 100644
index 0000000..4268ef1
--- /dev/null
+++ b/ckermit-8.0.211/ckuus7.c
@@ -0,0 +1,14933 @@
+#include "ckcsym.h"
+
+/*  C K U U S 7 --  "User Interface" for C-Kermit, part 7  */
+
+/*
+  Authors:
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    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 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"
+
+#ifdef VMS
+#ifndef TCPSOCKET
+#include <errno.h>
+#endif /* TCPSOCKET */
+#endif /* VMS */
+
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO                        /* Needed for ckocon.h */
+#define INCL_DOSMODULEMGR
+#include <os2.h>
+#undef COMMENT
+#else /* NT */
+#define APIRET ULONG
+#include <windows.h>
+#include <tapi.h>
+#include "cknwin.h"
+#include "ckntap.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)
+extern int mskkeys;
+#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;
+
+#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;
+
+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
+slrestor() {
+#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_xfw = sl_ssh_xfw;
+        sl_ssh_xfw_saved = 0;
+    }
+    if (sl_ssh_ver_saved) {
+        ssh_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 },
+    { "/timeout",      SL_TMO,    CM_ARG },
+    { "/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-telnet", NP_SSL_TELNET, 0 },
+#endif /* CK_SSL */
+    { "/telnet",     NP_TELNET, 0 },
+#ifdef CK_SSL
+    { "/tls",        NP_TLS,    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 OS2ORUNIX
+#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 /* OS2ORUNIX */
+
+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, 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 }
+};
+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 */
+#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 */
+
+#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_VT320;                 /* Terminal type, initially VT320 */
+int tt_type_mode = TT_VT320;            /* 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 }
+};
+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 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 */
+    { "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
+seton(prm) int *prm; {
+    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
+setonaut(prm) int *prm; {
+    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
+setnum(prm,x,y,max) int x, y, *prm, max; {
+    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
+setcc(dflt,var) char *dflt; int *var; {
+    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("?Invalid - %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 */
+
+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);
+
+
+
+
+
+int
+bkupnum(s,i) char * s; int *i; {
+    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;
+    long 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");
+        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
+doxdis(which) int which; {		/* 1 = Kermit, 2 = FTP */
+    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
+      ftp_dis = x;
+#endif /* NEWFTP */
+    return(success = 1);
+}
+#endif /* NOLOCAL */
+#endif /* NOXFER */
+
+int
+setfil(rmsflg) int rmsflg; {
+#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);
+    }
+}
+
+#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));
+      default:                          /* Shouldn't get here. */
+        return(-2);
+    }
+}
+#endif /* OS2 */
+
+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,"","vt320",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 */
+    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");
+#endif /* OS2 */
+    return(success = 0);
+}
+
+#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, * t;
+          k = ckstrncpy(iactbuf,"output ",132);
+          n = k;
+          q = &iactbuf[k];
+          p = tt_idlestr;
+          if (!p) p = "";
+          if (!*p) return("output (nothing)");
+          while ((c = *p++) && n < 131) {
+              c &= 0xff;
+              if (c == '\\') {
+                  if (n > 130) break;
+                  *q++ = '\\';
+                  *q++ = '\\';
+                  *q = NUL;
+                  n += 2;
+              } else if ((c > 31 && 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
+setlclcharset(x) int x; {
+    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
+setremcharset(x, z) int x, z; {
+    int i;
+
+#ifdef KUI
+    KuiSetProperty( KUI_TERM_REMCHARSET, (long) x, (long) 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
+setcmask(x) int x; {
+    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
+setautodl(x,y) int x,y; {
+    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 <remote> <local> */
+        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 ( 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 <local> */
+        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 <remote> <Graphic-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 ( 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);
+
+#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 <string> 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"
+                             , "\\v(newline)",&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, delay;
+        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 confirmed = 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 <terminal> <scancode> <value> 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 clear = 0, deflt = 0;
+    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, z;
+
+    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;
+
+    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_BUTTON) {              /* Shouldn't happen. */
+        printf("Internal parsing error\n");
+        return(-9);
+    }
+
+    /* MOUSE EVENT ... */
+
+    if ((button = cmkey(mousebuttontab,nmbtab,
+                        "Button number","1",
+                        xxstring)) < 0)
+      return(button);
+
+    if ((y =  cmkey(mousemodtab,nmmtab,
+                    "Keyboard modifier","none",
+                    xxstring)) < 0)
+      return(y);
+
+    event |= y;                         /* OR in the bits */
+
+    if ((y =  cmkey(mclicktab,nmctab,"","click",xxstring)) < 0)
+      return(y);
+
+    /* 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 */
+setsr(xx, rmsflg) int xx; int rmsflg; {
+    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);
+                    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;
+    char *s;
+    char c;
+
+    remfile = 0;
+    rempipe = 0;
+    remappd = 0;
+
+    if ((x = cmtxt(
+             "> filename, | command,\n\
+or type carriage return to confirm the command",
+                   "",&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);
+
+    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);
+    }
+    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
+remtxt(p) char ** p; {
+    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 = "";
+    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);
+    }
+    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. */
+        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);
+        }
+        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
+plogin(xx) int xx; {
+    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
+dormt(xx) int xx; {
+    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
+xxdormt(xx) int xx;
+#else /* NOLOCAL */
+int
+dormt(xx) int xx;
+#endif /* NOLOCAL */
+#else /* OS2 */
+int
+dormt(xx) int xx;
+#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;
+
+    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);
+        printf("?Sorry, REMOTE CDUP not supported yet\n");
+        return(-9);
+
+      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 = "";
+#endif /* DIRPWDPR */
+
+        debug(F110," password",s2,0);
+	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;
+
+#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
+setat(rmsflg) int rmsflg; {
+    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
+clsconnx(ask) int ask; {
+    int x, rc = 0;
+#ifdef NEWFTP
+    extern int ftpget, ftpisopen(), ftpbye();
+    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
+clskconnx(x) int x; {                   /* Close Kermit connection only */
+    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
+cx_fail(msg, text) int msg; char * text; {
+    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 */
+}
+
+#ifdef NETCONN
+/* 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, x, msg;
+    int _local = -1;
+
+    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",svc,SRVBUFSIZ);
+    debug(F101,"cx_net network type","",net);
+
+    msg = (gui == 0) && msgflg;		/* Whether to print messages */
+
+#ifndef NODIAL
+    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 /* NODIAL */
+
+    /* New connection wanted.  Make a copy of the host name/address... */
+
+    if (clskconnx(1) < 0)		/* Close current Kermit connection */
+      return(cx_fail(msg,"Error closing previous connection"));
+
+    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);
+
+#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 */
+
+    for (i = 0; i < n; i++) {		/* Loop for each entry found */
+	debug(F101,"cx_net loop i","",i);
+#ifndef NODIAL
+	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 */
+	{				/* No directory entries found. */
+	    ckstrncpy(line,hostname,LINBUFSIZ); /* Put this back... */
+	    /* 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) {
+            makestr(&ssh_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]) {
+                makestr(&ssh_prt,srvbuf);
+            } else
+                makestr(&ssh_prt,NULL);
+
+            if (command) {
+                makestr(&ssh_cmd,brstrip(command));
+                ssh_cas = param2;
+            } else
+                makestr(&ssh_cmd,NULL);
+
+            if (param1 > -1) {
+#ifndef SSHTEST
+                if (!sl_ssh_ver_saved) {
+                    sl_ssh_ver = ssh_ver;
+                    sl_ssh_ver_saved = 1;
+                }
+#endif /* SSHTEST */
+                ssh_ver = param1;
+            }
+            if (param3 > -1) {
+#ifndef SSHTEST
+                if (!sl_ssh_xfw_saved) {
+                    sl_ssh_xfw = ssh_xfw;
+                    sl_ssh_xfw_saved = 1;
+                }
+#endif /* SSHTEST */
+                ssh_xfw = param3;
+            }
+        } else                          /* NET_SSH */
+#endif /* SSHBUILTIN */
+#ifdef TCPSOCKET
+	  if (net == NET_TCPB) {
+            switch (protocol) {
+#ifdef CK_SSL
+	      case NP_SSL:
+                ttnproto = protocol;
+                ssl_only_flag = 1;
+                tls_only_flag = 0;
+                break;
+
+	      case NP_TLS:
+                ttnproto = protocol;
+                ssl_only_flag = 0;
+                tls_only_flag = 1;
+                break;
+
+	      case NP_SSL_TELNET:
+                ttnproto = NP_TELNET;
+                ssl_only_flag = 1;
+                tls_only_flag = 0;
+                break;
+
+	      case NP_TLS_TELNET:
+                ttnproto = NP_TELNET;
+                ssl_only_flag = 0;
+                tls_only_flag = 1;
+                break;
+#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
+                ssl_only_flag = 0;
+                tls_only_flag = 0;
+#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"));
+		} else if (line[0] != '*' && !ck_ntlm_is_valid(0)) {
+		    return(cx_fail(msg,"NTLM: Credentials are unavailable."));
+		}
+	    }
+#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 );
+
+#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);
+		    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
+	    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) {
+		int x;
+		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 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 || istncomport())	
+      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 CKLOGDIAL
+    dolognet();
+#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 */
+        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);
+}
+#endif /* NETCONN */
+
+/* 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 i, n, x, 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.columbia.edu/kermit/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 */
+		  ) {
+		  int x;		/* Find a safe, long buffer */
+		  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
+setlin(xx, zz, fc) 
+    int xx, zz, fc; 
+{
+    extern char pwbuf[], * g_pswd;
+    extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
+    int wait;
+    /* int tn_wait_sv; */
+    int mynet;
+    int _local = -1;
+    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, tx, nx;
+#ifdef OS2
+    struct FDB fl;
+#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;
+    }
+#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 */
+
+    if (xx == XYHOST) {                 /* SET HOST <hostname> */
+#ifndef NETCONN
+        makestr(&slmsg,"Network connections not supported");
+        printf("?%s\n",slmsg);
+        return(-9);
+#else /* NETCONN */
+#ifndef NOPUSH
+        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 */
+
+#ifdef SSHCMD
+        if (dossh) {                    /* SSH connection via pty */
+            int k;
+            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);
+            if (!*s) {
+                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);
+            }
+	    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);
+	    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 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" :
+                    "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 */
+        } 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) {
+                    strncat(line," ",LINBUFSIZ);
+                    strncat(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 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.
+*/
+
+/* Define NOSTAT if the <#>include causes trouble. */
+
+#ifndef NOSTAT
+#ifdef VMS
+#ifdef VAXC                             /* As it does in VAX C */
+#define NOSTAT
+#endif /* VAXC */
+#endif /* VMS */
+#endif /* NOSTAT */
+
+#ifndef NOSTAT
+#include <sys/stat.h>
+#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, */
+    long 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 */
+ckferror(n) int n; {
+    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
+z_open(name, flags) char * name; int flags; {
+    int i, n;
+    FILE * t;
+    char * mode;
+    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 < 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);
+    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 */
+        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';
+        }
+        z_inited = 1;                   /* Remember we did */
+    }
+    for (n = -1, i = 0; i < z_maxchan; i++) {
+        if (!z_file[i].z_fp) {
+            n = i;
+            break;
+        }
+    }
+    if (n < 0 || n >= z_maxchan)        /* Any free channels? */
+      return(z_error = FX_NMF);         /* No, fail. */
+    errno = 0;
+
+    z_file[n].z_flags = 0;              /* In case of failure... */
+
+    t = fopen(name, mode);              /* Try to open the file. */
+    if (!t) {                           /* Failed... */
+        debug(F111,"z_open error",name,errno);
+#ifdef EMFILE
+        if (errno == EMFILE)
+          return(z_error = FX_NMF);
+#endif /* EMFILE */
+        return(z_error = (errno ?  FX_SYS : FX_UNK)); /* Return error code */
+    }
+#ifdef NT
+#ifdef O_SEQUENTIAL
+    if (t)                              /* Caching hint for NT */
+      _setmode(_fileno(t),O_SEQUENTIAL);
+#endif /* O_SEQUENTIAL */
+#endif /* NT */
+    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_error = 0;
+    zfnqfp(name,CKMAXPATH,z_file[n].z_name); /* and the file's full name */
+    return(n);                          /* Return the channel number */
+}
+
+int
+z_close(channel) int channel; {         /* Close file on given channel */
+    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 (!(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 */
+    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 */
+    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
+z_out(channel,s,length,flags) int channel, flags, length; char * s; {
+    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 (!(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
+z_in(channel,s,buflen,length,flags)
+ int channel, buflen, length, flags; char * s;
+/* z_in */ {
+    int i, j, x;
+    FILE * t;
+    char * p;
+
+    if (!z_inited)                      /* Check everything... */
+      return(z_error = FX_NOP);
+    if (channel >= z_maxchan)
+      return(z_error = FX_CHN);
+    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 */
+        i = fread(s,1,length,t);
+#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 */
+        z_file[channel].z_nline = -1;   /* Current line no longer known */
+    } 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","",ftell(t));
+        for (i = 0; i < length; i++) {
+            if ((x = getc(t)) == EOF) {
+                debug(F101,"z_in getc error","",ftell(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 k, flag = 0;
+        long 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 = ftell(t);
+                    if (pos > -1) {
+                        pos -= (x - j - 1);
+                        x = fseek(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
+z_flush(channel) int channel; {         /* Flush output channel */
+    FILE * t;
+    int x;
+    if (!z_inited)                      /* Regular checks */
+      return(z_error = FX_NOP);
+    if (channel >= z_maxchan)
+      return(z_error = FX_CHN);
+    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, long pos)           /* Move file pointer to byte */
+#else
+z_seek(channel,pos) int channel; long pos; /* (seek to given position) */
+#endif /* CK_ANSIC */
+{
+    int i, x = 0, rc;
+    FILE * t;
+    if (!z_inited)                      /* Check... */
+      return(z_error = FX_NOP);
+    if (channel >= z_maxchan)
+      return(z_error = FX_CHN);
+    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 = fseek(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, long pos)           /* Move file pointer to line */
+#else
+z_line(channel,pos) int channel; long pos; /* (seek to given position) */
+#endif /* CK_ANSIC */
+{
+    int i, len, x = 0;
+    long current = 0L, prev = -1L, old = -1L;
+    FILE * t;
+    char tmpbuf[256];
+    if (!z_inited)                      /* Check... */
+      return(z_error = FX_NOP);
+    if (channel >= z_maxchan)
+      return(z_error = FX_CHN);
+    if (!(t = z_file[channel].z_fp))
+      return(z_error = FX_NOP);
+    debug(F101,"z_line pos","",pos);
+    if (pos < 0L) {                     /* EOF wanted */
+        long 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 = ftell(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 *
+z_getname(channel) int channel; {       /* Return name of file on channel */
+    FILE * t;
+    if (!z_inited) {
+        z_error = FX_NOP;
+        return(NULL);
+    }
+    if (channel >= z_maxchan) {
+        z_error = FX_CHN;
+        return(NULL);
+    }
+    if (!(t = z_file[channel].z_fp)) {
+        z_error = FX_NOP;
+        return(NULL);
+    }
+    return((char *)(z_file[channel].z_name));
+}
+
+int
+z_getmode(channel) int channel; {       /* Return OPEN modes of channel */
+    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 (!(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 (ftell(t) == statbuf.st_size)
+          x |= FM_EOF;
+#endif /* NOSTAT */
+    }
+    return(x);
+}
+
+long
+z_getpos(channel) int channel; {        /* Get file pointer position */
+    FILE * t;                           /* on this channel */
+    long x;
+    if (!z_inited)
+      return(z_error = FX_NOP);
+    if (channel >= z_maxchan)
+      return(z_error = FX_CHN);
+    if (!(t = z_file[channel].z_fp))
+      return(z_error = FX_NOP);
+    x = ftell(t);
+    return((x < 0L) ? (z_error = FX_SYS) : x);
+}
+
+long
+z_getline(channel) int channel; {       /* Get current line number */
+    FILE * t;                           /* in file on this channel */
+    long rc;
+    if (!z_inited)
+      return(z_error = FX_NOP);
+    if (channel >= z_maxchan)
+      return(z_error = FX_CHN);
+    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
+z_getfnum(channel) int channel; {       /* Get file number / handle */
+    FILE * t;                           /* for file on this channel */
+    if (!z_inited)
+      return(z_error = FX_NOP);
+    if (channel >= z_maxchan)
+      return(z_error = FX_CHN);
+    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.
+*/
+long
+z_count(channel, what) int channel, what; { /* Count bytes or lines in file */
+    FILE * t;
+    int i, x;
+    long pos, count = 0L;
+    if (!z_inited)                      /* Check stuff... */
+      return(z_error = FX_NOP);
+    if (channel >= z_maxchan)
+      return(z_error = FX_CHN);
+    if (!(t = z_file[channel].z_fp))
+      return(z_error = FX_NOP);
+    pos = ftell(t);                     /* Save current file pointer */
+    errno = 0;
+    z_error = 0;
+    if (what == RD_CHAR) {              /* Size in bytes requested */
+        if (!fseek(t,0L,2)) {           /* Seek to end */
+            count = ftell(t);           /* Get file pointer */
+            fseek(t,pos,0);             /* Restore file file pointer */
+            return(count);
+        } else                          /* Fallback in case seek fails */
+          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 = fseek(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 },
+    { "/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
+
+static struct keytab fskswtab[] = {
+    { "/absolute",  SEE_ABS,  0 },
+    { "/byte",      SEE_CHAR, 0 },
+    { "/character", SEE_CHAR, CM_INV },
+    { "/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 */
+
+int
+dofile(op) int op; {                    /* Do the FILE command */
+    char vnambuf[VNAML];                /* Buffer for variable names */
+    char *vnp = NULL;                   /* Pointer to same */
+    char zfilnam[CKMAXPATH+2];
+    char * p;
+    struct FDB fl, sw, nu;
+    long 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;
+
+    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 switches ere that take args */
+                if (!getval && (cmgkwflgs() & CM_ARG)) {
+                    printf("?This switch requires an argument\n");
+                    return(-9);         /* (none do...) */
+                }
+#endif /* COMMENT */
+                filmode |= cmresult.nresult; /* OR in the file mode */
+            } 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);
+            }
+        }
+        if (!(filmode & FM_RWA))        /* If no access mode specified */
+          filmode |= FM_REA;            /* default to /READ. */
+
+        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(F101,"fopen /append x","",x);
+        }
+        if (x == -9) {
+            if (zchko(s) < 0) {
+                printf("Can't create \"%s\"\n",s);
+                return(x);
+            }
+        } else 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 */
+        }
+        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 ((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 */
+          cmfdbi(&sw,                   /* Second FDB - switches */
+                 _CMKEY,                /* fcode */
+                 "Channel number; or keyword",
+                 "",
+                 "",                    /* addtl string data */
+                 1,                     /* addtl numeric data 1: tbl size */
+                 0,                     /* addtl numeric data 2: 4 = cmswi */
+                 xxstring,              /* Processing function */
+                 fclkwtab,              /* Keyword table */
+                 &nu                    /* Pointer to next FDB */
+                 );
+          cmfdbi(&nu,                   /* First FDB - command switches */
+                 _CMNUM,                /* 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 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);
+        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);
+                    }
+                    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);
+            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, k, 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);
+
+            line[0] = NUL;              /* Clear destination buffer */
+            if (rsize >= LINBUFSIZ)     /* Don't overrun it */
+              rsize = LINBUFSIZ - 1;
+
+            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;
+                      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);
+            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(" %ld %s%s\n",
+                     z_filcount,
+                     ((rsize == RD_CHAR) ? "byte" : "line"),
+                     ((z_filcount == 1L) ? "" : "s")
+                     );
+            return(success = (z_filcount > -1) ? 1 : 0);
+        }
+        cmfdbi(&sw,                     /* SEEK symbolic targets (EOF) */
+               _CMKEY,                  /* fcode */
+               "Channel number;\n or keyword",
+               "",
+               "",                      /* 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,                     /* Channel number */
+               _CMNUM,                  /* 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 == _CMNUM) {
+            y = cmresult.nresult;
+            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);
+        z = y;                          /* Convert to long */
+        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) {
+                long pos;
+                pos = z_getpos(n);
+                if (pos < 0L) {
+                    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) {
+                long pos;
+                pos = z_getline(n);
+                debug(F101,"FILE SEEK /LINE pos","",pos);
+                if (pos < 0L) {
+                    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);
+            }
+        }
+        return(success = y);
+
+      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: %4d\n", z_openmax);
+          printf("Maximum for FILE OPEN:  %4d\n", z_maxchan);
+          printf("Files currently open:   %4d\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 > -1) {
+                      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
+                        printf(" %ld",z_getpos(i)); /* And file position too */
+                  }
+                  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 ((rc = z_flush(n)) < 0) {
+            printf("?FLUSH failed - Channel %d: %s\n",n,ckferror(rc));
+            return(-9);
+        }
+        return(success = 1);
+
+      case FIL_STA:                     /* STATUS */
+        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);
+        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 {
+            long 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:        %ld\n",z_count(n,RD_CHAR));
+            printf(" At byte:     %ld\n",z_getpos(n));
+            xx = z_getline(n);
+            if (xx > -1)
+              printf(" At line:     %ld\n",xx);
+            return(success = 1);
+        }
+      default:
+        return(-2);
+    }
+}
+#endif /* CKCHANNELIO */
+
+#ifndef NOSETKEY
+/* Save Key maps and in OS/2 Mouse maps */
+int
+savkeys(name,disp) char * name; int disp; {
+    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 <termtype> 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 */
+
+#ifdef CK_RECALL
+_PROTOTYP(int savhistory, (char *, int));
+#endif /* CK_RECALL */
+
+int
+dosave(xx) int xx; {
+    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));
+        break;
+#endif /* NORECALL */
+
+#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
+readtext(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; {
+#ifdef CK_RECALL
+    extern int on_recall;               /* Around Password prompting */
+#endif /* CK_RECALL */
+    int rc;
+#ifndef NOLOCAL
+#ifdef OS2
+    extern int 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
+readpass(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; {
+    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 int 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:"<none>");
+#endif /* OS2 */
+    printf("  Anonymous Initfile:  %s\r\n",anonfile?anonfile:"<none>");
+    printf("  Anonymous Login:     %d\r\n",ckxanon);
+    printf("  Anonymous Root:      %s\r\n",anonroot?anonroot:"<none>");
+#endif /* CK_LOGIN */
+    printf("  Bannerfile:          %s\r\n",bannerfile?bannerfile:"<none>");
+    printf("  CDfile:              %s\r\n",cdmsgfile[0]?cdmsgfile[0]:"<none>");
+    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:"<none>");
+    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:"<none>");
+    printf("  Initfile:            %s\r\n",kermrc?kermrc:"<none>");
+    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);
+    printf("  Timeout (seconds):   %d\r\n",logintimo);
+    printf("  Userfile:            %s\r\n",userfile?userfile:"<none>");
+#ifdef CK_LOGIN
+#ifdef CKWTMP
+    printf("  Wtmplog:             %d\r\n",ckxwtmp);
+    printf("  Wtmpfile:            %s\r\n",wtmpfile?wtmpfile:"<none>");
+#endif /* CKWTMP */
+#endif /* CK_LOGIN */
+    printf("  Xferfile:            %s\r\n",xferfile?xferfile:"<none>");
+    printf("  Xferlog:             %d\r\n",xferlog);
+#else /* IKSDCONF */
+    printf("?Nothing to show.\r\n");
+#endif /* IKSDCONF */
+    return(success = 1);
+}
+
+#ifdef CK_AUTHENTICATION
+int
+sho_auth(cx) int cx; {
+    extern int auth_type_user[], cmd_rows;
+    int i;
+    char * p;
+    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;
+          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;
+            }
+
+#ifdef CK_SSL
+            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 *)
+                  SSL_CTX_new((SSL_METHOD *)TLSv1_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 {                  /* Temporary array for switch values */
+        char * sval;                    /* String value */
+        int ival;                       /* Integer value */
+    } pv[KRB_I_MAX+1];                  /* This many */
+    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 */
+    }
+
+    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:<filename> */
+                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:<minutes> */
+                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:<minutes> */
+                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:<timestamp> */
+                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:<name> */
+                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:<name> */
+                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:<name> */
+                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:<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:{<address-list>} */
+                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 CK_PAM
+    extern int guest;
+#endif /* CK_PAM */
+    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 CK_PAM
+        && guest
+#endif /* CK_PAM */
+        ) {
+        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 */
+            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);
+            }
+            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);
+    }
+
+    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 */
diff --git a/ckermit-8.0.211/ckuusr.c b/ckermit-8.0.211/ckuusr.c
new file mode 100644
index 0000000..8545f89
--- /dev/null
+++ b/ckermit-8.0.211/ckuusr.c
@@ -0,0 +1,13121 @@
+#ifdef SSHTEST
+#define SSHBUILTIN
+#endif /* SSHTEST */
+
+#include "ckcsym.h"
+char *userv = "User Interface 8.0.278, 12 Mar 2004";
+
+/*  C K U U S R --  "User Interface" for C-Kermit (Part 1)  */
+
+/*
+  Authors:
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    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.
+*/
+
+/*
+  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
+  system- 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
+    ckmain.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"
+
+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 */
+
+#ifndef NOICP
+#ifdef CKLEARN
+#ifdef VMS
+#include <time.h>			/* For CKLEARN */
+#endif /* VMS */
+#endif /* CKLEARN */
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO			/* Needed for ckocon.h */
+#include <os2.h>
+#undef COMMENT
+#else
+#define APIRET ULONG
+#include <windows.h>
+#include <tapi.h>
+#include "cknwin.h"
+#include "ckntap.h"			/* CK_TAPI definition */
+#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 tt_status[VNUM];
+#endif /* NOTERM */
+int display_demo = 1;
+#include "ckossh.h"
+#ifdef KUI
+#include "ikui.h"
+#endif /* KUI */
+#endif /* OS2 */
+
+int optlines = 0;
+int didsetlin = 0;
+
+#ifdef NEWFTP
+extern int ftpget, ftpisopen(), doftpres();
+_PROTOTYP(int doftptyp,(int));
+#endif /* NEWFTP */
+
+#ifdef VMS
+extern int batch;
+#endif /* VMS */
+
+#ifdef datageneral
+#include <packets:common.h>
+#define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
+#endif /* datageneral */
+
+extern int xcmdsrc, hints, cmflgs, whyclosed;
+
+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 long 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 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 */
+extern char lblbuf[];			/* Buffer for labels */
+int m_found;				/* MINPUT result */
+int i_active = 0;			/* INPUT command is active */
+char *ms[MINPMAX];			/* Pointers to MINPUT strings */
+static int mp[MINPMAX];			/* and 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 */
+  innomatch = 0,			/* INPUT /NOMATCH */
+  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] = { ' ',' ',' ',' ',' ',' ',' ' };
+
+#define INPSW_NOM 1
+struct keytab inputsw[] = {
+    { "/nomatch", INPSW_NOM, 0 }
+};
+static int ninputsw = sizeof(inputsw)/sizeof(struct keytab);
+
+#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 */
+/* Keywords must be in lowercase and 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 },
+    { "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 NOLOCAL
+    { "connect",     XXCON, CM_LOC },	/* Begin terminal connection */
+#else
+    { "connect",     XXNOTAV, CM_LOC },
+#endif /* NOLOCAL */
+    { "continue",    XXCONT,  CM_INV },	/* CONTINUE */
+#ifndef NOFRILLS
+#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) */
+    { "debug",       XXDEBUG, CM_INV },
+    { "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 */
+    { "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 },
+
+#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 */
+
+    { "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 */
+#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 */
+
+#ifndef NOXFER
+    { "move",        XXMOVE, 0 },	/* MOVE  */
+#endif /* NOXFER */
+
+#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 */
+#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 */
+
+    { "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
+    { "res",         XXRSEN, CM_INV|CM_ABR }, /* RESEND */
+    { "rese",        XXRSEN, CM_INV|CM_ABR }, /* RESEND */
+    { "resend",      XXRSEN, 0 },	/* RESEND */
+#else
+    { "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
+    { "rmkdir",      XXRMKD, CM_INV },	/* REMOTE MKDIR */
+#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 */
+
+#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 */
+
+    { "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 */
+
+    { "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
+    { "xmit",        XXTRA, CM_INV },	/* Synonym for TRANSMIT */
+#else
+    { "xmit",        XXNOTAV, CM_INV },
+#endif /* NOXMIT */
+
+#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 */
+
+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
+    { "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 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 },
+#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 */
+#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 */
+#endif /* NOXFER */
+    { "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
+int    ssh_pf_lcl_n = 0,
+       ssh_pf_rmt_n = 0;
+struct ssh_pf ssh_pf_lcl[32] = { 0, NULL, 0 }; /* SSH Port Forwarding */
+struct ssh_pf ssh_pf_rmt[32] = { 0, NULL, 0 }; /* structs... */
+extern char * ssh_hst, * ssh_cmd, * ssh_prt;
+extern int    ssh_ver,   ssh_xfw;
+char * ssh_tmpuid = NULL, *ssh_tmpcmd = NULL, *ssh_tmpport = NULL,
+     * ssh_tmpstr = NULL;
+
+int
+ sshk_type = SSHKT_2D,			/* 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;
+
+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 },
+    { "/x11-forwarding", SSHSW_X11, CM_ARG },
+    { "", 0, 0 }
+};
+int nsshopnsw = (sizeof(sshopnsw) / sizeof(struct keytab)) - 1;
+
+static struct keytab sshkwtab[] = {
+    { "add",                 XSSH_ADD, 0 },
+    { "agent",               XSSH_AGT, 0 },
+    { "clear",               XSSH_CLR, 0 },
+    { "forward-local-port",  XSSH_FLP, CM_INV },
+    { "forward-remote-port", XSSH_FRP, CM_INV },
+    { "key",                 XSSH_KEY, 0 },
+    { "open",                XSSH_OPN, 0 },
+    { "v2",                  XSSH_V2,  0 },
+    { "", 0, 0 }
+};
+static int nsshcmd = (sizeof(sshkwtab) / sizeof(struct keytab)) - 1;
+
+static struct keytab ssh2tab[] = {
+    { "rekey", XSSH2_RKE, 0 },
+    { "", 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;
+
+static struct keytab sshkv1[] = {	/* SET SSH KEY V1 command table */
+    { "set-comment",  1, 0 }
+};
+
+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 }
+};
+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 },
+    { "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! */
+
+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 /* 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 },
+    { "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 },
+#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));
+
+#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 */
+
+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 },
+#endif /* NOCSETS */
+    { "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 */
+#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 },
+#endif /* TNCODE */
+    { "terminal",      SHTER,  CM_LOC },
+#endif /* NOLOCAL */
+#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 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 */
+
+static struct keytab typetab[] = {	/* TYPE command switches */
+    { "/count",          TYP_COU, 0 },
+#ifdef UNICODE
+    { "/character-set",  TYP_XIN, 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 */
+    { "/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_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
+setlocus(x, isauto) int x, isauto; {
+    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.\n",
+		 x ? "LOCAL" : "REMOTE"
+		 );
+	locus = x;
+#ifdef OS2
+#ifdef KUI
+	KuiSetProperty(KUI_LOCUS,x,0);
+#endif /* KUI */
+    }
+#endif /* OS2 */
+}
+
+VOID
+setautolocus(x) int x; {
+    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);
+}
+
+/* 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 ) );
+_PROTOTYP (int doincr,   ( int  ) );
+#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
+doend(x) int x; {
+#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
+doxsend(cx) int cx; {
+    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 {			/* Temporary array for switch values */
+	char * sval;
+	int ival;
+    } pv[SND_MAX+1];
+    struct FDB sf, sw, fl, cm;		/* FDBs for each parse function */
+    int mlist = 0;			/* Flag for MSEND or MMOVE */
+    char * m;				/* For making help messages */
+    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 long 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 */
+    }
+#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:
+	    if (!getval) break;
+	    if ((x = cmnum("Size in bytes","0",10,&y,xxstring)) < 0)
+	      goto xsendx;
+	    pv[n].ival = y;
+	    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) */
+	    if (!getval) break;
+	    if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0)
+	      goto xsendx;
+	    pv[n].ival = y;
+	    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 */
+	    if (getval) {
+		if ((x = cmnum("number of Kbytes to send",
+			   "1024",10,&y,xxstring)) < 0)
+		  goto xsendx;
+	    } else
+	      y = 1024;
+	    pv[n].ival = y;
+	    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].ival > 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].ival > 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 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].ival > 0) {		/* Handle /CALIBRATE */
+	if (confirmed) {
+	    calibrate = pv[SND_CAL].ival * 1024L;
+	    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 = 0L;
+	    pv[SND_CAL].ival = 0L;
+	}
+    }
+#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 = 0L;
+#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 */
+	    ) {
+	    int y = 1;
+	    if (!wild)
+	      y = zchki(s);
+	    if (y < 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].ival > -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].ival;
+	} else
+	  sendstart = 0L;
+	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].ival > -1)
+	  sndsmaller = pv[SND_SMA].ival;
+	if (pv[SND_LAR].ival > -1)
+	  sndlarger = pv[SND_LAR].ival;
+	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 {		/* Temporary array for switch values */
+    char * sval;
+    int ival;
+} 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
+doxconn(cx) int cx; {
+    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 */
+    }
+    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 */
+
+    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
+doadd(cx,fc) int cx, fc; {
+#ifdef PATTERNS
+    char * tmp[FTPATTERNS];
+    char **p = NULL;
+    int i, j, k, 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
+addsend(cx) int cx; {
+#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
+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;
+/* 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
+arrayitoa(x) int x; {			/* Array index to array letter */
+    if (x == 1)
+      return(64);
+    else if (x < 0 || x > (122 - ARRAYBASE))
+      return(-1);
+    else
+      return(x + ARRAYBASE);
+}
+
+int
+arrayatoi(c) int c; {			/* Array letter to array index */
+    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 */
+dodcl(cx) int cx; {
+    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
+		      );
+	    if ((rc = cmfld((char *)tmp,"",&s,xxstring)) < 0) { /* Get field */
+		if (rc == -3)		/* If answer is empty, we're done */
+		  break;
+		else			/* Parse error, free temp pointers */
+		  goto dclx;
+	    }
+	    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,0);		/* 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
+clrarray(cx) int cx; {
+    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][28];
+extern int aa_dim[CMDSTKL][28];
+
+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
+doeval(cx) int cx; {
+    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);
+    if (x < 0) {
+	if (x == -9) {
+	    if (zchko(s) < 0) {
+		printf("Can't create \"%s\"\n",s);
+		return(x);
+	    }
+	} else if (x != -3)
+	  return(x);
+    }
+    if (x == -3)
+      tmpbuf[0] = NUL;
+    else {
+	ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+	if (iswild((char *)tmpbuf)) {
+	    printf("?A single file please\n");
+	    return(-9);
+	}
+    }
+    if ((z = cmcfm()) < 0) return(z);
+    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;
+    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);
+#endif /* OS2 */
+
+#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 /* NOHELP */
+
+#ifndef NOHTTP
+#ifdef TCPSOCKET
+static struct keytab sslswtab[] = {
+    { "/ssl", 1, 0 },
+    { "/tls", 1, 0 }
+};
+
+#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 */
+	  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);
+	  if ((x = cmofi("Local filename",lfile,&s,xxstring)) < 0)
+	    if (x != -3)
+	      goto xhttp;
+	  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;
+	  }
+
+	havehost:			/* Come here with s -> host */
+#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
+learncmd(s) char *s; {			/* Record commands in learned script */
+    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 */
+
+
+/*  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
+docmd(cx) int cx; {
+    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 scipts 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(lblbuf,s,LBLSIZ);
+	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(lblbuf,brstrip(s),LBLSIZ);
+#endif /* COMMENT */
+	s = lblbuf;
+	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(&macroname,mactab[mx].kwd); /* Save name */
+
+		if ((y = cmtxt("optional arguments","",&s,xxstring)) < 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);
+	    /* Defer evaluation of variables until the commands are exec'd */
+	    if ((y = cmtxt("Braced list of commands","",&s,NULL)) < 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 = atmbuf;
+	    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); /* Precheck for > 1 SEXP */
+	debug(F101,"sexp split","",q->a_size);
+
+	if (q->a_size == 1) {		/* We should get exactly one back */
+	    char * result, * dosexp();
+	    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)
+		  printf(" %s\n",result ? 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 preserver 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
+    if (cx == XXBUG) {			/* BUG */
+	if ((x = cmcfm()) < 0) return(x);
+	return(dobug());
+    }
+#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 == XXDIR || cx == XXLS || cx == XXLDIR) { /* DIRECTORY or LS */
+#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 ||
+              isguest))
+            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;
+		GetShortPathName(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 */
+	  printf("%s\n",(char *)line);
+
+	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,3);
+	debug(F101,"HELP command x","",x);
+	if (x == -5) {
+	    y = chktok(toktab);
+	    debug(F101,"HELP cmkey token","",y);
+	    /* ungword(); */
+	    switch (y) {
+#ifndef NOPUSH
+	      case '!': x = XXSHE; 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 */
+	      case '&': x = XXECH; break;
+	      default:
+		printf("\n?Invalid - %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;
+	extern int ispattern, isjoin;
+
+	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";
+	}
+	innomatch = 0;			/* Initialize switch value(s) */
+
+	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 */
+
+	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 */
+		if (cmresult.nresult == INPSW_NOM) /* /NOMATCH */
+		  innomatch = 1;
+		m = "Seconds to wait for input,\n or time of day hh:mm:ss";
+		cmfdbi(&nu,_CMNUM,m,"","",10,0,xxstring,NULL,&fl);
+		cmfdbi(&fl,_CMFLD,"","","",0,0,xxstring,NULL,NULL);
+		fc = cmfdb(&nu);	/* Parse something */
+		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
+	for (y = 0; y < MINPMAX; y++) {	/* Initialize strings */
+	    mp[y] = 0;			/* Assume it's not a pattern */
+	    if (ms[y]) {
+		free(ms[y]);		/* Free old strings, if any */
+		ms[y] = NULL;
+	    }
+	}
+	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))) {
+			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 (ispattern) mp[k] = 1;
+			debug(F111,"MINPUT",ms[k],ispattern);
+			k++;
+		    }
+		}
+	    }
+	    keepallchars = 0;
+	} else {
+#endif /* CK_MINPUT */
+
+	    /* INPUT or REINPUT */
+
+	    if ((y = cmtxt("Material to be input","",&s,xxstring)) < 0)
+	      return(y);
+	    mp[0] = ispattern ? 1 : 0;
+	    makestr(&(ms[0]),brstrip(s));
+	    ms[1] = NULL;
+
+#ifdef CK_MINPUT
+	}
+#endif /* CK_MINPUT */
+
+#ifdef COMMENT
+	printf("/NOMATCH=%d\n",innomatch);
+	printf("Timeout=%d\n",x);
+	return(1);
+#endif	/* COMMENT */
+
+	if (cx == XXINP || cx == XXMINP) { /* Not REINPUT... */
+	    i_active = 1;
+	    /* Go try to input the search string */
+	    success = doinput(x,ms,mp,innomatch);
+	    i_active = 0;
+	} else {			/* REINPUT */
+	    success = doreinp(x,ms[0],ispattern);
+	}
+	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;
+
+	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() */
+	) {
+	int rx = 0;
+	char * p = NULL;
+	int i /* ,n */ ;
+#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 */
+            unsigned long 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);
+            unsigned long 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;
+	int xx;
+#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 */
+
+#ifdef ANYSSH
+    if (cx == XXSSH) {			/* SSH (Secure Shell) */
+	extern int netsave;
+#ifdef SSHBUILTIN
+	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 */
+	       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);
+	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;
+	}
+	switch (cmresult.nresult) {	/* SSH keyword */
+	  case XSSH_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",
+		   "",
+		   "",
+		   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_cas = (cmresult.nresult == SSHSW_SUB);
+			break;
+		      case SSHSW_X11:
+			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);
+            }
+	    makestr(&ssh_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) {
+                makestr(&ssh_prt,ssh_tmpport);
+                makestr(&ssh_tmpport,NULL);
+            } else
+                makestr(&ssh_prt,NULL);
+
+            if (ssh_tmpcmd) {
+                makestr(&ssh_cmd,brstrip(ssh_tmpcmd));
+                makestr(&ssh_tmpcmd,NULL);
+            } else
+                makestr(&ssh_cmd,NULL);
+
+            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;
+            }
+            if (tmpxfw > -1) {
+#ifndef SSHTEST
+                if (!sl_ssh_xfw_saved) {
+                    sl_ssh_xfw = ssh_xfw;
+                    sl_ssh_xfw_saved = 1;
+                }
+#endif /* SSHTEST */
+                ssh_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 */
+	    k = ttopen(line,&x,mdmtyp, 0);
+	    if (k < 0) {
+		printf("?Unable to connect to %s\n",ssh_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_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 ((y = cmkey(sshclr,nsshclr,"","", xxstring)) < 0) {
+	        if (y == -3) {
+		    printf("?clear what?\n");
+		    return(-9);
+		}
+	        return(y);
+	    }
+	    if ((x = cmcfm()) < 0)
+	      return(x);
+	    switch (y) {
+	      case SSHC_LPF:
+                ssh_pf_lcl_n = 0;
+		break;
+	      case SSHC_RPF:
+		ssh_pf_rmt_n = 0;
+		break;
+	      default:
+		return(-2);
+	    }
+            return(success = 1);	/* or whatever */
+
+	  case XSSH_AGT: {		/* SSH AGENT */
+	      int doeach = 0;
+	      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);
+	      }
+	  }
+	  case XSSH_ADD: {		/* SSH ADD */
+	      /* ssh add { local, remote } port host port */
+	      int cx, i, j, k;
+	      char * h;
+	      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);
+	  }
+	  /* Not supporting arbitrary forwarding yet */
+	  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;
+              if ((x = cmnum(cmresult.nresult == XSSH_FLP ?
+                              "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);
+              }
+	      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);
+	      switch (cmresult.nresult) {
+                case XSSH_FLP:	/* SSH FORWARD-LOCAL-PORT */
+#ifndef SSHTEST
+                  ssh_fwd_local_port(li_port,fw_host,to_port);
+#endif /* SSHTEST */
+		  return(success = 1);
+		case XSSH_FRP:	/* SSH FORWARD-REMOTE-PORT */
+#ifndef SSHTEST
+                  ssh_fwd_remote_port(li_port,fw_host,to_port);
+#endif /* SSHTEST */
+		  return(success = 1);
+	      }
+	      return(success = 1);
+	  }
+	case XSSH_V2:		/* SSH V2 */
+	  if ((cx = cmkey(ssh2tab,nssh2tab,"","", xxstring)) < 0)
+	    return(cx);
+	  switch (cx) {
+	    case XSSH2_RKE:
+	      if ((x = cmcfm()) < 0)
+		return(x);
+#ifndef SSHTEST
+	      ssh_v2_rekey();
+#endif /* SSHTEST */
+	      return(success = 1);
+	    default:
+	      return(-2);
+	  }
+	case XSSH_KEY:
+	  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 = 1024, keytype = SSHKT_2R;
+	      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("","1024",10,&z,xxstring)) < 0)
+			return(y);
+		      if (z < 512 || z > 4096) {
+			  printf("?Out range - min: 512, max: 4096\n");
+			  return(-9);
+		      }
+		      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,"",
+				     "v2-rsa",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 = 0;
+	      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));
+	    }
+	    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);
+	  }
+	  default:
+	    return(-2);
+	}
+#else  /* SSHBUILTIN */
+#ifdef SSHCMD
+	x = nettype;
+	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_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);
+              }
+              makestr(&ssh_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) {
+                  makestr(&ssh_prt,ssh_tmpport);
+                  makestr(&ssh_tmpport,NULL);
+              } else
+                  makestr(&ssh_prt,NULL);
+
+              /* Set the Subsystem to Kermit */
+              ssh_cas = 1;
+              makestr(&ssh_cmd,"kermit");
+
+              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_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_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);
+              }
+              makestr(&ssh_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) {
+                  makestr(&ssh_prt,ssh_tmpport);
+                  makestr(&ssh_tmpport,NULL);
+              } else
+                  makestr(&ssh_prt,NULL);
+
+              /* Set the Subsystem to Kermit */
+              ssh_cas = 1;
+              makestr(&ssh_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_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_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_cas || strcmp(ssh_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 /* NETCONN */
+#endif /* NOLOCAL */
+
+#ifndef NOXMIT
+    if (cx == XXTRA) {			/* TRANSMIT */
+	extern int xfrxla;
+	int i, 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 height = 0, 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
+	char guibuf[128], * gui_title = NULL;
+	int  gui = 0;
+#endif /* NT */
+#ifndef NOCSETS
+	extern int tcsr, tcsl;
+#endif /* NOCSETS */
+#endif /* OS2 */
+#endif /* UNICODE */
+
+	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;
+
+		  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
+	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 /* 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);
+
+	printf("\n%s, for%s\n Numeric: %ld",versio,ckxsys,vernum);
+	printf("\n\n");
+        printf("Authors:\n");
+	printf(" Frank da Cruz, Columbia University\n");
+        printf(" Jeffrey Eric Altman, Secure Endpoints, Inc. %s\n",
+	       "<jaltman@secure-endpoints.com>"
+	       );
+	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
+	shoreg();
+#else
+#ifdef COMMENT
+	hmtopline = n+1;
+	hmsga(copyright);
+	hmtopline = 0;
+#endif /* COMMENT */
+#endif /* OS2 */
+	return(success = 1);
+    }
+
+    if (cx == XXCPR) {			/* COPYRIGHT or LICENSE */
+	if ((y = cmcfm()) < 0)
+          return(y);
+#ifdef OS2
+	if (inserver) {			/* Free WIKSD */
+	    extern char * wiksdcpr[];
+	    hmsga(wiksdcpr);
+	} else
+#endif /* OS2 */
+	  hmsga(copyright);
+	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);
+	    if (x < 0) printf("?Write error\n");
+	} else {
+	    x = -1;
+	    printf("?File or log not open\n");
+	}
+	return(success = (x == 0) ? 1 : 0);
+    }
+#endif /* NOFRILLS */
+
+#ifndef NOXFER
+    if (cx == XXASC || cx == XXBIN) {
+	if ((x = cmcfm()) < 0) return(x);
+#ifdef NEWFTP
+	if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+	  return(success = doftptyp((cx == XXASC) ? 0 : 1));
+#endif /* NEWFTP */
+	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 == 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);
+	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)
+      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());
+
+    if (cx == XXDEBUG) {		/* DEBUG */
+#ifndef DEBUG
+	int dummy = 0;
+	return(seton(&dummy));
+#else
+	return(seton(&deblog));
+#endif /* DEBUG */
+    }
+
+#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, *p, 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;
+	    GetShortPathName(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 */
+	}
+    }
+    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 */
diff --git a/ckermit-8.0.211/ckuusr.h b/ckermit-8.0.211/ckuusr.h
new file mode 100644
index 0000000..eecb78c
--- /dev/null
+++ b/ckermit-8.0.211/ckuusr.h
@@ -0,0 +1,2974 @@
+/*  C K U U S R . H  --  Symbol definitions for C-Kermit ckuus*.c modules  */
+
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 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 */
+
+#ifdef BIGBUFOK
+#define FNVALL 10238			/* Function return value length */
+#define MAXARGLEN 8191			/* 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 */
+#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 */
+#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 LBLSIZ 50			/* Maximum length for a GOTO label */
+#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;
+};
+
+#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 */
+
+#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 <sys/types.h>
+#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_MAX  47			/* 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 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 */
+
+/* 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 */
+
+/* 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_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)
+#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 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 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 paramaters */
+#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 */
+/* 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_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 */
+#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 */
+
+/* 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 RGB */
+
+/* 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 */
+
+/* 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 */
+#define VN_REGN   106			/* Registration Name */
+#define VN_REGO   107			/* Registration Organization */
+#define VN_REGS   108			/* Registration Serial number */
+#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 */
+#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 */
+
+#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() */
+
+#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 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
+
+#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 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 */
+
+#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 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 dohrmt, (int) );
+_PROTOTYP( int doif, (int) );
+_PROTOTYP( int doinput, (int, char *[], 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 *, int, int) );
+_PROTOTYP( int ckdial, (char *, int, int, int, int) );
+_PROTOTYP( int hmsg, (char *) );
+_PROTOTYP( int hmsga, (char * []) );
+_PROTOTYP( int mlook, (struct mtab [], char *, int) );
+_PROTOTYP( int mxlook, (struct mtab [], char *, int) );
+_PROTOTYP( int mxxlook, (struct mtab [], char *, int) );
+_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 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 *, int *) );
+_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
+_PROTOTYP( int settapi, (void) ) ;
+#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 */
diff --git a/ckermit-8.0.211/ckuusx.c b/ckermit-8.0.211/ckuusx.c
new file mode 100644
index 0000000..e2c89c6
--- /dev/null
+++ b/ckermit-8.0.211/ckuusx.c
@@ -0,0 +1,9387 @@
+#include "ckcsym.h"
+
+/*  C K U U S X --  "User Interface" common functions. */
+
+/*
+  Authors:
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    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 module contains user interface functions needed by both the interactive
+  user interface and the command-line-only user interface.
+*/
+
+/* Includes */
+
+#include "ckcdeb.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckuusr.h"
+#include "ckcxla.h"
+
+#ifndef NOHTERMCAP
+#ifdef NOTERMCAP
+#define NOHTERMCAP
+#else
+#ifndef BSD44
+#define NOHTERMCAP
+#else
+#ifdef __bsdi__
+#define NOHTERMCAP
+#else
+#ifdef OPENBSD
+#define NOHTERMCAP
+#else
+#ifdef MACOSX
+#define NOHTERMCAP
+#endif /* MACOSX */
+#endif /* OPENBSD */
+#endif /* __bsdi__ */
+#endif /* BSD44 */
+#endif /* NOTERMCAP */
+#endif /* NOHTERMCAP */
+
+#ifndef NOTERMCAP
+#ifdef BSD44
+#ifndef NOHTERMCAP
+#include <termcap.h>
+#endif /* NOHTERMCAP */
+#endif /* BSD44 */
+#else  /* !BSD44 */
+#ifdef linux
+#include <term.h>
+#endif /* linux */
+#endif /* NOTERMCAP */
+
+#ifdef OS2
+#include <string.h>
+_PROTOTYP(char * os2_gethostname, (void));
+#define getpid _getpid
+#endif /* OS2 */
+#ifdef BSD44
+#include <errno.h>
+#endif /* BSD44 */
+
+extern xx_strp xxstring;
+
+#ifdef OS2
+#include "ckcnet.h"
+#else /* OS2 */
+_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 <windows.h>
+#include <tapi.h>
+#include "ckntap.h"
+#else /* NT */
+#define INCL_VIO
+#include <os2.h>
+#endif /* NT */
+#ifdef COMMENT                          /* Would you believe */
+#undef COMMENT                          /* <os2.h> 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 <signal.h>
+#endif /* WINTCP */
+
+#ifdef VMS
+#include <descrip.h>
+#include <ssdef.h>
+#include <stsdef.h>
+#ifndef OLD_VMS
+#include <lib$routines.h>  /* Not for VAX C 2.3 */
+#else
+#include <libdef.h>
+#endif /* OLD_VMS */
+#ifdef WINTCP
+#include <signal.h>
+#endif /* WINTCP */
+#endif /* VMS */
+
+#ifdef DCLFDOPEN
+/* fdopen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * fdopen, (int, char *) );
+#endif /* DCLFDOPEN */
+
+#ifdef DCLPOPEN
+/* popen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * popen, (char *, char *) );
+#endif /* DCLPOPEN */
+
+int tt_crd = 0;                         /* Carriage return display */
+int interrupted = 0;                    /* Interrupted from keyboard flag */
+static 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 */
+
+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 */
+#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 <sysid.h>
+extern int con_reads_mt, conint_ch, conint_avl;
+#endif /* datageneral */
+
+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 */
+
+_PROTOTYP( VOID screenc, (int, char, long, char *) );
+_PROTOTYP( VOID screeng, (int, char, long, 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, long, long) );
+_PROTOTYP( static long shoetl, (long, long, long, long) );
+#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 *
+gskreason(n) int n; {
+    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 long 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, ffc, tfc, rptn, fsize, filcps, tfcps, cps, peakcps;
+
+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 <setjmpex.h>
+#else /* NT */
+#include <setjmp.h>
+#endif /* NT */
+#include "ckcsig.h"
+extern ckjmpbuf cmjbuf;
+#endif /* NOCCTRAP */
+
+extern int xfiletype, nscanfile;
+
+int
+shoesc(escape) int escape; {
+    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 long sndlarger, sndsmaller, calibrate, skipbup;
+extern int rmailf, rprintf;
+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 =  -1L;
+    sndsmaller = -1L;
+#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 <string.h> */
+_PROTOTYP( char * strerror, (int) );
+#endif /* CK_ANSILIBS */
+#ifdef CKROOT
+    if (ckrooterr)
+      return("Off limits");
+#endif /* CKROOT */
+    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
+matchname(filename, local, os) char * filename; int local; int os; {
+    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..4, on success indicating file type:
+     0 = 7-bit text (flag = -1)
+     1 = UTF-8 text (flag = -1)
+     2 = UCS-2 text (flag =  0: big-endian; flag = 1: little-endian)
+     3 = 8-bit text (flag =  0: no C1 bytes; flag = 1: includes C1 bytes)
+     4 = 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
+scanfile(name,flag,nscanfile) char * name; int * flag, nscanfile; {
+    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 <LF><NUL> sequences */
+    int crlf = 0;			/* Number of <CRLF> 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 != 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);
+}
+
+/*  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,
+    long minsiz, long 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; long minsiz,maxsiz; int nbu,nxlist; char ** xlist;
+#endif /* CK_ANSIC */
+/* fileselect */ {
+    char *fdate;
+    int n;
+    long z;
+
+    if (!sa) sa = "";
+    if (!sb) sb = "";
+    if (!sna) sna = "";
+    if (!snb) snb = "";
+
+#ifdef CKSYMLINK
+#ifndef NOICP
+#ifndef NOXFER
+    if (nolinks) {
+	long zz;
+	zz = zgetfs(f);
+	debug(F111,"fileselect NOLINKS zgetfs",f,zz);
+	if (zz < 0L)
+	  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);
+	}
+    }
+    if (minsiz > -1L || maxsiz > -1L) { /* Smaller or larger */
+	z = zchki(f);			/* Get size */
+	debug(F101,"fileselect filesize","",z);
+	if (z < 0)
+	  return(1);
+	if ((minsiz > -1L) && (z >= minsiz)) {
+	    debug(F111,"fileselect minsiz skipping",f,minsiz);
+	    /* tlog(F111,"Skipping (too big)",f,z); */
+	    return(0);
+	}
+	if ((maxsiz > -1L) && (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 dialcapas, dialfc;
+    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
+sdebu(len) int len; {
+    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
+rdebu(d,len) CHAR *d; int len; {
+    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
+fatal(msg) char *msg; {
+    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 *
+bldlen(str,dest) char *str, *dest; {
+    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
+fnparse(string) char *string; {
+    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 */
+        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 *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 */
+dbchr(c) int c; {
+    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 <sys/utsname.h>
+#endif /* apollo */
+#endif /* BSD44 */
+#else
+#ifdef BELLV10
+#include <utsname.h>
+#endif /* BELLV10 */
+#endif /* SVORPOSIX*/
+
+#ifdef CKSYSLOG
+extern char uidbuf[], * clienthost;
+#endif /* CKSYSLOG */
+
+VOID
+ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
+
+#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;
+    int havefull = 0;
+#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) {
+	if (sig == SIGINT)
+	  debug(F101,"trap caught SIGINT","",sig);
+	else
+	  debug(F101,"trap caught signal","",sig);
+    }
+#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 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 300
+
+/*  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, long n)
+#else
+dotlog(f,s1,s2,n) int f; long 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 %ld %s",s1,n,s2);
+        if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+        break;
+      case F001:                        /* 1, " n" */
+        sprintf(sp," %ld",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] %ld",s2,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: %ld",s1,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: %ld",s1,((*s2 == ':') ? "" : " "),s2,n);
+        if (zsoutl(ZTFILE,s) < 0) tralog = 0;
+        break;
+      default:
+        sprintf(sp,"?Invalid format for tlog() - %ld",n);
+        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, long fs, int fm, int status, char * msg)
+#else
+doxlog(x, fn, fs, fm, status, msg)
+    int x; char * fn; long 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,"%ld",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;
+
+#ifdef GFTIMER
+	debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000));
+
+        cps = (long)((CKFLOAT) fs / fpxfsecs);
+        sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps);
+#else
+        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,(long)spsiz, " packet length");
+        else if (what & W_RECV || what & W_REMO)
+          xxscreen(SCR_QE,0,(long)urpsiz," packet length");
+        xxscreen(SCR_QE,0,(long)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 long oldffc = 0L;
+static long 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 = 0L;                        /*  Reset this */
+    dots = 0L;                          /*  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 > -1L) {			/* Size */
+        sprintf(fbuf,"Size: %ld, Type: ",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 */
+    long howfar;                        /* How far into file */
+    long pd;                            /* Percent done, this file     */
+    long tp;                            /* Transfer rate, entire batch */
+    long ps;                            /* Packet size, current packet */
+    long 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 == 0L) return;        /* Empty file, don't bother */
+        pd = (fsize > 99L) ? (howfar / (fsize / 100L)) : 0L;
+        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 > 99L) ? (howfar / (fsize / 100L)) : 0L;
+        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 > 0L) ? (fsize - howfar) * (et - fsecs) / howfar : 0L;
+#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%9ld%5ld%%%8ld%8ld ", CR, howfar, pd, tp, ps);
+        else
+          sprintf(buffer, "%c%9ld      %8ld%8ld ", CR, 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,long n,char *s)
+#else
+ckscreen(f,c,n,s) int f; char c; long 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) (%ld byte%s)",
+#ifdef NOICP
+                   (binary ? "binary" : "text")
+#else
+                   gfmode(binary,0)
+#endif /* NOICP */
+                   , n, n == 1L ? "" : "s");
+#ifdef UNIX
+            fflush(stdout);
+#endif /* UNIX */
+            return;
+        }
+#ifdef MAC
+        sprintf(buf,", Size: %ld",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
+                printf(": OK (%0.3f sec, %ld cps)\n",fpxfsecs,
+                       (long)((CKFLOAT)ffc / fpxfsecs));
+#else
+                printf(": OK (%d sec, %ld cps)\n",xfsecs,ffc/xfsecs);
+#endif /* GFTIMER */
+                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 == 1L) ? "" : "s"));
+                printf(", %ld byte%s", tfc, ((tfc == 1L) ? "" : "s"));
+#ifdef GFTIMER
+                printf(", %0.3f sec, %ld cps", fptsecs, tfcps);
+#else
+                printf(", %ld 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_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
+ermsg(msg) char *msg; {                 /* Print error message */
+    debug(F110,"ermsg",msg,0);
+    if (local)
+      xxscreen(SCR_EM,0,0L,msg);
+    tlog(F110,"Protocol Error:",msg,0L);
+}
+#endif /* NOXFER */
+
+VOID
+setseslog(x) int x; {
+    seslog = x;
+#ifdef KUI
+    KuiSetProperty(KUI_TERM_CAPTURE,x,0);
+#endif /* KUI */
+}
+
+VOID
+doclean(fc) int fc; {                   /* General cleanup */
+#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
+doexit(exitstat,code) int exitstat, code; {
+    extern int x_logged, quitting;
+#ifdef OS2
+    extern int display_demo;
+    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 int vmode;
+
+        /* If there is a demo screen to be displayed, display it */
+        if (display_demo) {
+            demoscrn(VCMD);
+            display_demo = 0;
+        }
+#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 */
+
+#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 */
+
+/* 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 "<NUL>" and "<LF>".
+
+   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, long n)
+#else
+dodebug(f,s1,s2,n) int f; char *s1, *s2; long 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,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,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,"=%ld\n",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 == 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=%ld\n",s1,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]=%ld\n",s1,s2,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... */
+
+extern int slogts;			/* Session Log timestamps */
+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 */
+    int oktolog = 0;
+#ifndef NOLOCAL
+    if (!seslog)
+      return;
+
+    if ((sessft != XYFT_T) ||
+	(c != '\0' &&
+#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 (!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')		/* If this is not eol */
+	      tsstate = 1;		/* go to in-a-line state. */
+	} else if (c == '\n') {		/* In a line */
+	    tsstate = 0;		/* If eol go to between-lines state. */
+	}
+    }
+    if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */
+      goto xlogchar;
+    return;
+
+  xlogchar:
+    conoll("");
+    conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
+    setseslog(0);
+    zclose(ZSFILE);
+#endif /* NOLOCAL */
+}
+
+VOID
+logstr(s, len) char * s; int len; {     /* Log string to session log */
+#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
+#undef 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 <curses.h>
+/* 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 <ncurses.h>
+#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 <curses.h>
+#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 */
+
+#ifdef NOTERMCAP
+static int notermcap = 1;
+#else
+static int notermcap = 0;
+#endif /* NOTERMCAP */
+
+#ifndef NODISPLAY
+#ifdef OSK
+VOID
+#else
+#ifdef CK_ANSIC
+void
+#endif /* CKANSIC */
+#endif /* OSK */
+fxdinit(xdispla) int xdispla; {
+#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;
+            }
+            debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL);
+            debug(F001,"fxdinit trmbuf","",trmbuf);
+#ifdef COMMENT
+            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 <smgdef.h>                     /* use this on VAX C 2.4 */
+/* #include <smgmsg.h> */
+#else
+#include <smg$routines.h>               /* 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
+move(row, col) int row, col; {
+    /* 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 <stdarg.h>
+_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
+ck_curpos(row, col) {
+    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:
+*/
+
+static int
+touchwin(x) int x; {
+    return(0);
+}
+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
+ck_curpos(row, col) int row, col; {
+    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() {
+    viocell cell;
+    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() {
+    USHORT row, col;
+    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
+ck_curpos(row, col) int row, col; {
+    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 */
+ck_termset(x) int x; {
+    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,"");
+            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,"");
+            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,"");
+            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
+ck_curpos(row, col) int row, col; {
+#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, 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, (long) CW_PCD, (long) 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, (long) CW_PCD, (long) 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 long old_tr = -1L;               /* Time remaining previously */
+
+static long
+#ifdef CK_ANSIC
+shoetl(long old_tr, long cps, long fsiz, long howfar)
+#else
+shoetl(old_tr, cps, fsiz, howfar) long old_tr, cps, fsiz, howfar;
+#endif /* CK_ANSIC */
+/* shoetl */ {                          /* Estimated time left in transfer */
+    long tr;                            /* Time remaining, seconds */
+
+#ifdef GFTIMER
+    if (fsiz > 0L && cps > 0L)
+      tr = (long)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps);
+    else
+      tr = -1L;
+#else
+    tr = (fsiz > 0L && cps > 0L) ?
+      ((fsiz - howfar) / cps) :
+        -1L;
+#endif /* GFTIMER */
+    move(CW_TR,22);
+    if (tr > -1L) {
+        if (tr != old_tr) {
+            printw("%s",hhmmss(tr));
+#ifdef KUI
+#ifndef K95G
+            KuiSetProperty(KUI_FILE_TRANSFER, (long)CW_TR, (long)hhmmss(tr));
+#endif /* K95G */
+#endif /* KUI */
+            clrtoeol();
+        }
+    } else {
+        printw("(unknown)");
+#ifdef KUI
+#ifndef K95G
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "(unknown)" );
+#endif /* K95G */
+#endif /* KUI */
+        clrtoeol();
+    }
+    return(tr);
+}
+
+static long
+#ifdef CK_ANSIC
+shocps(int pct, long fsiz, long howfar)
+#else
+shocps(pct, fsiz, howfar) int pct; long fsiz, howfar;
+#endif /* CK_ANSIC */
+/* shocps */ {
+#ifdef CPS_WEIGHTED
+    static long oldffc = 0L;
+#endif /* CPS_WEIGHTED */
+#ifdef GFTIMER
+    CKFLOAT secs, xx;
+#else
+    long 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, (long) CW_CP, (long) 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, (long) CW_CP, (long) 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, (long) CW_CP, (long) 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;
+    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, (long) CW_TYP, (long) 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 */
+    "<ERROR>",				/* 17 In case new types are added */
+    "<ERROR>",				/* 18 but nobody remembers to update */
+    "<ERROR>",				/* 19 this table ... */
+    NULL				/* 20 */
+};
+static int nnetname = (sizeof(netname) / sizeof(char *));
+
+#endif /* NETCONN */
+
+#ifdef CK_ANSIC
+void
+screenc(int f, char c,long n,char *s)
+#else
+#ifdef MYCURSES
+VOID
+#else
+int
+#endif /* MYCURSES */
+screenc(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 */
+/* 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 fsiz = -1L;   /* Copy of file size */
+    static long fcnt = 0L;    /* Number of files transferred */
+    static long fbyt = 0L;    /* Total file bytes of all files transferred */
+    static long 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 <andy@vlsi.cs.caltech.edu>)
+           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, (long) CW_DIR, (long) 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, (long) CW_LIN, (long) 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 */
+                 ) {
+		secure = 1;
+	    }
+	    if (secure) {
+#ifdef KUI
+#ifndef K95G
+                char buf[30];
+                sprintf(buf,"%s (SECURE)",xname);
+                KuiSetProperty(KUI_FILE_TRANSFER,
+                               (long) CW_SPD,
+                               (long) buf
+                               );
+#endif /* K95G */
+#endif /* KUI */
+                printw("%s (SECURE)",xname);
+            } else {
+                printw("%s",xname);
+#ifdef KUI
+#ifndef K95G
+                KuiSetProperty(KUI_FILE_TRANSFER,
+                               (long) CW_SPD,
+                               (long) xname
+                               );
+#endif /* K95G */
+#endif /* KUI */
+            }
+#else
+            printw("(network)");
+#ifdef KUI
+#ifndef K95G
+            KuiSetProperty(KUI_FILE_TRANSFER,
+                           (long) CW_SPD,
+                           (long) "(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,
+                                   (long) CW_SPD,
+                                   (long) "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,
+                                   (long) CW_SPD,
+                                   (long) speedbuf
+                                   );
+#endif /* K95G */
+#endif /* KUI */
+                }
+            } else {
+                printw("unknown");
+#ifdef KUI
+#ifndef K95G
+                KuiSetProperty(KUI_FILE_TRANSFER,
+                               (long) CW_SPD,
+                               (long) "(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,
+                       (long) CW_PAR,
+                       (long) 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><CR> 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, <Enter> 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, <CR> 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 = -1L;                     /* Invalidate previous file size */
+        move(CW_PCD,22);                /* Erase percent done from last time */
+#ifdef KUI
+#ifndef K95G
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
+#endif /* K95G */
+#endif /* KUI */
+        clrtoeol();
+        move(CW_SIZ,22);                /* Erase file size from last time */
+#ifdef KUI
+#ifndef K95G
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
+#endif /* K95G */
+#endif /* KUI */
+        clrtoeol();
+        move(CW_ERR,22);                /* And last error message */
+#ifdef KUI
+#ifndef K95G
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
+#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,13);
+                printw("FTP PUT:");
+	    } else
+#endif /* NEWFTP */
+#ifdef CK_RESEND
+            switch (sendmode) {		/* Kermit */
+              case SM_RESEND:
+                move(CW_NAM,11);
+                printw("RESENDING:");
+                break;
+              default:
+                move(CW_NAM,13);
+                printw("SENDING:");
+                break;
+            }
+#else
+            move(CW_NAM,13);
+            printw("SENDING:");
+#endif /* CK_RESEND */
+
+        } else if (what & W_RECV) {	/* If we're receiving... */
+#ifdef NEWFTP
+	    if (what & W_FTP) {		/* FTP */
+                move(CW_NAM,13);
+                printw("FTP GET:");
+	    } else {
+#endif /* NEWFTP */
+		move(CW_NAM,11);
+		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,11);            /* (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, (long) CW_NAM, (long) 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, (long) CW_NAM, (long) 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, (long) CW_NAM, (long) 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 > -1L) {
+#ifdef KUI
+#ifndef K95G
+            KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
+#endif /* K95G */
+#endif /* KUI */
+            printw("%ld",n);
+        }
+        clrtoeol();
+#ifdef COMMENT
+        move(CW_PCD, 8);
+        if (fsiz > -1L) {               /* Put up percent label */
+            pctlbl = 1;
+	    clrtoeol();
+            printw("Percent Done:");
+        }
+#else
+	move(CW_PCD, 8);
+	clrtoeol();
+        if (fsiz > -1L) {               /* 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,
+                           (long) CW_PAR,
+                           (long) 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, (long) CW_PL, (long) 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, (long) CW_PC, (long) 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, (long) CW_WS, (long) 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, (long) CW_PR, (long) 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, (long) CW_PT, (long) 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("%ld", ffc);
+            }
+#ifdef KUI
+#ifndef K95G
+            KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) 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,
+                               (long) CW_PR, (long) 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, (long) CW_ERR, (long) 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, (long) CW_ERR, (long) 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,
+                           (long) CW_ERR,
+                           (long) "Damaged Packet"
+                           );
+#endif /* K95G */
+#endif /* KUI */
+            clrtoeol();
+            break;
+          case 'q':                     /* Ctrl-C or connection lost */
+            move(CW_MSG,22);
+	    clrtoeol();
+            if (!s) s = "";
+            printw(*s ? s : "User interruption or connection lost");
+#ifdef KUI
+#ifndef K95G
+            KuiSetProperty(KUI_FILE_TRANSFER,
+                           (long) CW_MSG,
+                           (long) 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,
+                           (long) CW_ERR,
+                           (long) "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,
+                               (long) CW_PR, (long) 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("%ld", ffc);
+#ifdef KUI
+#ifndef K95G
+            KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) 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("%ld", ffc);
+#ifdef KUI
+#ifndef K95G
+            KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) 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, (long) CW_MSG, (long) "" );
+#endif /* K95G */
+#endif /* KUI */
+        clrtoeol(); refresh();
+#endif /* COMMENT */
+
+        move(CW_TR, 22);
+#ifdef KUI
+#ifndef K95G
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
+#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,
+                           (long) CW_MSG,
+                           (long) "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,
+                           (long) CW_ERR,
+                           (long) "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,
+                           (long) CW_ERR,
+                           (long) "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,
+                           (long) CW_ERR,
+                           (long) "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, (long) CW_ERR, (long) 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,(long) CW_ERR,(long) errbuf);
+#endif /* K95G */
+#endif /* KUI */
+            } else {
+                printw("Refused");
+#ifdef KUI
+#ifndef K95G
+                KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"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,(long)CW_ERR,(long)"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,(long)CW_MSG,(long)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, (long) CW_ERR,
+                       (long) "*** 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, (long) CW_CP, tfcps);
+#endif /* K95G */
+#endif /* KUI */
+          printw("%ld", tfcps);
+          clrtoeol();
+          if (success) {
+              move(CW_MSG,22);          /* Print statistics in message line */
+              clrtoeol();
+          }
+          if (success) {
+              sprintf(msgbuf,
+                      "SUCCESS.  Files: %ld, Bytes: %ld, %ld CPS",
+                      filcnt - filrej,
+                      fbyt,
+                      tfcps
+                      );
+              printw("%s", msgbuf);
+#ifdef KUI
+#ifndef K95G
+              KuiSetProperty(KUI_FILE_TRANSFER,
+                             (long) CW_MSG,
+                             (long) 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,
+                         (long) CW_TR,
+                         (long) 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, (long) CW_ERR, (long) 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_XD:                      /* X-packet data */
+        pct = oldpct = 0;
+        move(CW_NAM,22);
+        printw("%s",s);
+#ifdef KUI
+#ifndef K95G
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) 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, (long) CW_DIR, (long) 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,
+                       (long) CW_ERR,
+                       (long) "*** 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
+VOID
+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 long fsiz = -1L;   /* Copy of file size */
+    static long fcnt = 0L;    /* Number of files transferred */
+    static long fbyt = 0L;    /* Total file bytes of all files transferred */
+    static long 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,"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, (long) CW_DIR, (long) zgtdir() );
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN,
+                        (long) (
+#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 */
+                 ) {
+		secure = 1;
+	    }
+	    if (secure) {
+                char buf[30];
+                sprintf(buf,"%s (SECURE)",xname);
+                KuiSetProperty(KUI_FILE_TRANSFER,
+                               (long) CW_SPD,
+                               (long) buf
+                               );
+            } else {
+                KuiSetProperty(KUI_FILE_TRANSFER,
+                               (long) CW_SPD,
+                               (long) xname
+                               );
+            }
+#else
+            KuiSetProperty(KUI_FILE_TRANSFER,
+                           (long) CW_SPD,
+                           (long) "(network)"
+                           );
+#endif /* NETCONN */
+        } else {
+            if (speed < 0L)
+              speed = ttgspd();
+            if (speed > 0L) {
+                if (speed == 8880) {
+                    KuiSetProperty(KUI_FILE_TRANSFER,
+                                   (long) CW_SPD,
+                                   (long) "75/1200"
+                                   );
+                } else {
+                    char speedbuf[64] ;
+                    sprintf(speedbuf, "%ld", speed);
+                    KuiSetProperty(KUI_FILE_TRANSFER,
+                                   (long) CW_SPD,
+                                   (long) speedbuf
+                                   );
+                }
+            } else {
+                KuiSetProperty(KUI_FILE_TRANSFER,
+                               (long) CW_SPD,
+                               (long) "(unknown)"
+                               );
+            }
+        }
+        KuiSetProperty(KUI_FILE_TRANSFER,
+                       (long) CW_PAR,
+                       (long) 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 = -1L;                     /* Invalidate previous file size */
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
+
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) 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, (long) CW_NAM, (long) s );
+#ifdef OS2
+        SaveCmdMode(0, 0);
+#endif /* OS2 */
+        return;
+
+      case SCR_FS:                      /* File size */
+        fsiz = n;
+        if (fsiz > -1L) {
+            KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
+        }
+        if (fsiz > -1L) {               /* 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,
+                           (long) CW_PAR,
+                           (long) 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,
+				    (long) CW_LIN,
+				    (long) 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,
+				(long) CW_TMO,
+				(long) msgbuf
+				);
+            } else {
+                xx = (rttdelay + 500) / 1000;
+                if (xx != oldrtt || rcvtimo != oldtim) {
+                    char msgbuf[64];
+                    sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo);
+                    KuiSetProperty( KUI_FILE_TRANSFER,
+				    (long) CW_TMO,
+				    (long) 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, (long) CW_PL, (long) x );
+            oldlen = x;
+        }
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) 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, (long) CW_WS, (long) ws );
+            }
+        }
+        errors = retrans + crunched + timeouts;
+        if (errors != oldtry) {         /* Retry count, if changed */
+            KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) 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, (long) CW_PT, (long) 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, (long) CW_FFC, (long) ffc);
+            }
+            KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) 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,
+                               (long) CW_PR,
+			       (long) errors
+                               );
+                }
+                oldtry = errors;
+                if (s) if (*s) {
+                    KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
+            }
+            break;
+
+          case 'E':                     /* Error packet */
+            if (*s) {
+                KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) 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,
+                           (long) CW_ERR,
+                           (long) "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,
+                           (long) CW_MSG,
+                           (long) s
+                           );
+            break;
+          case 'T':                     /* Timeout */
+            cps = shocps((int) pct, fsiz, howfar);
+            /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
+            KuiSetProperty(KUI_FILE_TRANSFER,
+                           (long) CW_ERR,
+                           (long) "Timeout"
+                           );
+            errors = retrans + crunched + timeouts;
+            if (errors != oldtry) {     /* Error count, if changed */
+                KuiSetProperty(KUI_FILE_TRANSFER,
+                               (long) CW_PR, (long) 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, (long) CW_FFC, (long) 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, (long) CW_FFC, (long) ffc);
+#ifdef COMMENT
+            pct = 100;
+            oldpct = 0;
+#endif /* COMMENT */
+        }
+#endif /* COMMENT */
+
+        KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
+
+        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,
+                                (long) CW_MSG,
+                                (long) "Delete OK"
+                                );
+	    } else {
+		fbyt += ffc;
+                KuiSetProperty(KUI_FILE_TRANSFER,
+                                (long) CW_MSG,
+                                (long) "Transfer OK"
+                                );
+	    }
+            return;
+
+          case ST_DISC:                 /* Discarded */
+            KuiSetProperty(KUI_FILE_TRANSFER,
+                           (long) CW_ERR,
+                           (long) "File discarded"
+                           );
+#ifdef COMMENT
+            pct = oldpct = 0;
+#endif /* COMMENT */
+            return;
+
+          case ST_INT:                  /* Interrupted */
+            KuiSetProperty(KUI_FILE_TRANSFER,
+                           (long) CW_ERR,
+                           (long) "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,
+                           (long) CW_ERR,
+                           (long) errbuf
+                           );
+#ifdef COMMENT
+            pct = oldpct = 0;
+#endif /* COMMENT */
+            return;
+        }
+          case ST_ERR:                  /* Error message */
+            if (!s) s = (char *)epktmsg;
+            KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) 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,(long) CW_ERR,(long) errbuf);
+            } else {
+                KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
+            }
+#ifdef COMMENT
+            pct = oldpct = 0;
+#endif /* COMMENT */
+            return;
+
+          case ST_INC:
+            KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
+#ifdef COMMENT
+            pct = oldpct = 0;
+#endif /* COMMENT */
+            return;
+
+          case ST_MSG:
+            KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
+            return;
+
+          default:                      /* Bad call */
+            KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
+                       (long) "*** screen() called with bad status ***" );
+            return;
+        }
+
+      case SCR_TC: {                    /* Transaction complete */
+          char msgbuf[128];
+          KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
+          if (success) {
+              sprintf(msgbuf,
+                      "SUCCESS.  Files: %ld, Bytes: %ld, %ld CPS",
+                      filcnt - filrej,
+                      fbyt,
+                      tfcps
+                      );
+              KuiSetProperty(KUI_FILE_TRANSFER,
+                             (long) CW_MSG,
+                             (long) msgbuf
+                             );
+          }
+          KuiSetProperty(KUI_FILE_TRANSFER,
+                         (long) CW_TR,
+                         (long) 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, (long) CW_ERR, (long) 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, (long) CW_NAM, (long) 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, (long) CW_DIR, (long) s );
+#ifdef OS2
+        SaveCmdMode(0, 0);
+#endif /* OS2 */
+        return;
+
+      default:                          /* Bad call */
+        KuiSetProperty(KUI_FILE_TRANSFER,
+                       (long) CW_ERR,
+                       (long) "*** 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
+ck_curpos(row, col) {
+    return(-1);
+}
+
+int
+ck_cls() {
+    return(-1);
+}
+
+int
+ck_cleol() {
+    return(-1);
+}
+#endif /* CK_CURPOS */
+
+#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
+updslot(n) int n; {                     /* Update our slot */
+    int rc = 0;
+    long 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 (fseek(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
+initslot(n) int n; {                    /* Initialize slot */
+    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
+slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; {
+    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
+slotdir(s1,s2) char * s1, * s2; {       /* Update current directory */
+    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
+freeslot(n) int n; {
+    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  */
+
+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], * s;
+    int j, k, n, x, rc = -1;
+    int lockfd, tries, haveslot = 0;
+    long lockpid, 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);
+    if (lockfd < 0) {
+        debug(F111,"getslock temp lockfile create failure", tmplck, errno);
+        return(-1);
+    }
+    /* Write my (decimal) PID into the temp file */
+
+    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
+            ftruncate(fileno(dbfp),i);
+#endif /* COHERENT */
+            x = 0;
+            fseek(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),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 */
diff --git a/ckermit-8.0.211/ckuusy.c b/ckermit-8.0.211/ckuusy.c
new file mode 100644
index 0000000..479ee36
--- /dev/null
+++ b/ckermit-8.0.211/ckuusy.c
@@ -0,0 +1,4624 @@
+#include "ckcsym.h"
+#define XFATAL fatal
+
+/*  C K U U S Y --  "User Interface" for Unix Kermit, part Y  */
+
+/*  Command-Line Argument Parser */
+
+/*
+  Authors:
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    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 "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 <signal.h>
+
+#ifdef OS2
+#include <io.h>
+#ifdef KUI
+#include "ikui.h"
+extern struct _kui_init kui_init;
+#endif /* KUI */
+#endif /* OS2 */
+
+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 */
+#endif /* OS2 */
+
+#ifdef CK_NETBIOS
+extern unsigned char NetBiosAdapter;
+#endif /* CK_NETBIOS */
+
+#ifdef XFATAL
+#undef XFATAL
+#endif /* XFATAL */
+
+#ifdef TNCODE
+_PROTOTYP(static int dotnarg, (char x) );
+#endif /* TNCODE */
+#ifdef RLOGCODE
+_PROTOTYP(static int dorlgarg, (char x) );
+#endif /* RLOGCODE */
+#ifdef SSHBUILTIN
+_PROTOTYP(static int dossharg, (char x) );
+#endif /* SSHBUILTIN */
+
+int haveftpuid = 0;			/* Have FTP user ID */
+static int have_cx = 0;			/* Have connection */
+
+#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 */
+_PROTOTYP(static int pmsg, (char *) );
+_PROTOTYP(static int fmsg, (char *) );
+static int pmsg(s) char *s; { printf("%s\n", s); return(0); }
+static int fmsg(s) char *s; { 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;
+
+#ifndef URLBUFLEN
+#define URLBUFLEN 1024
+#endif /* URLBUFLEN */
+static char urlbuf[URLBUFLEN];
+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 ]
+
+  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
+urlparse(s,url) char *s; struct urldata * url; {
+    char * p = NULL, * urlbuf = NULL;
+    int x;
+
+    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;
+    }
+    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;
+            }
+	    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);
+
+            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",
+"  -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",
+"  -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",
+"  -d                Turn on debug mode\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
+fatal2(msg1,msg2) char *msg1, *msg2; {
+    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);
+}
+
+static SIGTYP
+#ifdef CK_ANSI
+cl_int(int dummy)
+#else /* CK_ANSI */
+cl_int(dummy) int dummy;
+#endif /* CK_ANSI */
+{					/* Command-line interrupt handler */
+    doexit(BAD_EXIT,1);
+    SIGRETURN;
+}
+
+#ifdef NEWFTP
+extern int ftp_action, ftp_cmdlin;
+
+static int
+xx_ftp(host, port) char * host, * port; {
+#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 */
+    ""
+};
+
+#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 /* 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 <arg>%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;
+
+    signal(SIGINT,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);
+#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 */
+	  {
+	      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 */
+		      int xx;
+		      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
+                        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 /* 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... */
+          extern char * ssh_hst, * ssh_cmd, * ssh_prt;
+	  debug(F100,"ssh personality","",0);
+#ifdef CK_URL
+	  if (haveurl) {
+              makestr(&ssh_hst,g_url.hos);
+              makestr(&ssh_prt,g_url.svc);
+	      ckstrncpy(ttname,ssh_hst,TTNAMLEN+1);
+              ckstrncat(ttname,":",TTNAMLEN+1);
+              ckstrncat(ttname,ssh_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);
+                      makestr(&ssh_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);
+                          makestr(&ssh_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);
+                          makestr(&ssh_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);
+                              makestr(&ssh_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[32];
+            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 },
+#endif /* KUI */
+    { "noescape",    XA_NOESCAPE, CM_PRE },
+#endif /* OS2 */
+    { "nointerrupts",XA_NOIN, 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 */
+#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:<filename>";
+            xarghlp[j] = "File to display upon startup or IKSD login";
+            break;
+          case XA_CDFI:                 /* "--cdfile" */
+            xopthlp[j] = "--cdfile:<filename>";
+            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:<filename>";
+            xarghlp[j] = "File containing custom info for HELP command";
+            break;
+          case XA_IKFI:                 /* "--xferfile" */
+            xopthlp[j] = "--xferfile:<filename> [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:<filename> [IKSD only]";
+            xarghlp[j] = "Initialization file for anonymous users.";
+            break;
+#ifdef CK_PERM
+          case XA_PERM:                 /* "--permissions" */
+            xopthlp[j] = "--permissions:<octalnum> [IKSD only]";
+            xarghlp[j] = "Permissions for files uploaded by anonymous users.";
+            break;
+#endif /* CK_PERM */
+#ifdef UNIX
+          case XA_ROOT:                 /* "--root" */
+            xopthlp[j] = "--root:<directory> [IKSD only]";
+            xarghlp[j] = "File-system root for anonymous users.";
+            break;
+#else /* UNIX */
+#ifdef CKROOT
+          case XA_ROOT:                 /* "--root" */
+            xopthlp[j] = "--root:<directory> [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:<digit> [IKSD only]";
+            xarghlp[j] = "Syslog recording level, 0-6.";
+            break;
+#endif /* CKSYSLOG */
+          case XA_USFI:                 /* "--userfile" */
+            xopthlp[j] = "--userfile:<filename> [IKSD only]";
+            xarghlp[j] = "Forbidden user file.";
+            break;
+#ifdef CKWTMP
+          case XA_WTFI:                 /* "--wtmpfile" */
+            xopthlp[j] = "--wtmpfile:<filename> [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:<seconds> [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 IKSDB
+          case XA_DBAS:
+            xopthlp[j] = "--database:{on,off}";
+            xarghlp[j] = "Enable/Disable IKSD database (IKSD only)";
+            break;
+          case XA_DBFI:
+            xopthlp[j] = "--dbfile:<filename>";
+            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_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;
+       }
+    }
+}
+
+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] = "Make a 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();
+}
+
+int
+doxarg(s,pre) char ** s; int pre; {
+#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 */
+
+    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 */
+
+      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 */
+
+#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 /* 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 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, * ck_s_xver;
+	  printf("%s",ck_s_ver);
+	  if (*ck_s_xver)
+	    printf(" [%s]\n",ck_s_xver);
+	  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;
+    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:
+        os2settitle(p,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 */
+
+      default:
+        return(-1);
+    }
+    return(0);
+}
+
+#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);
+        if (*s)
+	  makestr(&anonfile,s);
+        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);
+        if (*s)
+	  makestr(&userfile,s);
+        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 COMMENT
+	  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++;
+		      }
+	      }
+	      xargc++, xargv--;		/* Adjust argv/argc */
+	      if (!fil2snd && z == 0) {
+#ifdef VMS
+		  XFATAL("%CKERMIT-E-SEARCHFAIL, no files for -s");
+#else
+		  XFATAL("No files for -s");
+#endif /* VMS */
+	      }
+	      if (z > 1) {
+		  XFATAL("-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 COMMENT
+	  case '-':			/* Extended commands... */
+            if (doxarg(xargv,0) < 0) {
+                XFATAL("Extended option error");
+            } /* Full thru... */
+	  case '+':			/* Extended command for prescan() */
+            return(0);
+#else  /* COMMENT */
+	  case '-':
+	  case '+':
+	    XFATAL("Extended options not configured");
+#endif /* COMMENT */
+
+/*
+ * -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
+ * -K                Refuse use of authentication; do not send username
+ * -l user           Set username and request Telnet authentication
+ * -L                Negotiate Telnet Binary Output only
+ * -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
+ * -f                Forward credentials to host
+ * -k realm          Set default realm
+ *
+ */
+	  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 '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 COMMENT
+	  case '-':			/* Extended commands... */
+            if (doxarg(xargv,0) < 0) {
+            XFATAL("Extended option error");
+            } /* Full thru... */
+	  case '+':			/* Extended command for prescan() */
+            return(0);
+#else  /* COMMENT */
+	  case '-':
+	  case '+':
+	    XFATAL("Extended options not configured");
+#endif /* COMMENT */
+
+/*
+ * -d                Debug
+ * -l user           Set username
+ *
+ */
+	  case 'h':			/* help */
+	    usage();
+	    doexit(GOOD_EXIT,-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 COMMENT
+	  case '-':			/* Extended commands... */
+            if (doxarg(xargv,0) < 0) {
+                XFATAL("Extended option error");
+            } /* Full thru... */
+	  case '+':			/* Extended command for prescan() */
+            return(0);
+#else  /* COMMENTP */
+	  case '-':
+	  case '+':
+	    XFATAL("Extended options not configured");
+#endif /* COMMENT */
+
+/*
+ * -d                Debug
+ * -l user           Set username
+ *
+ */
+	  case 'h':			/* help */
+	    usage();
+	    doexit(GOOD_EXIT,-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 /* SSHBUILTIN */
+
+#else /* No command-line interface... */
+
+extern int xargc;
+int
+cmdlin() {
+    if (xargc > 1) {
+        XFATAL("Sorry, command-line options disabled.");
+    }
+}
+#endif /* NOCMDL */
diff --git a/ckermit-8.0.211/ckuver.h b/ckermit-8.0.211/ckuver.h
new file mode 100644
index 0000000..2d01207
--- /dev/null
+++ b/ckermit-8.0.211/ckuver.h
@@ -0,0 +1,1229 @@
+/* ckuver.h -- C-Kermit UNIX Version heralds */
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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
+#ifdef MACOSX103
+#define HERALD " Mac OS X 10.3"
+#else
+#define HERALD " Mac OS X"
+#endif /* MACOSX103 */
+#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__
+#ifdef NETBSD16
+#define HERALD " NetBSD 1.6"
+#else
+#ifdef NETBSD15
+#define HERALD " NetBSD 1.5"
+#else
+#define HERALD " NetBSD"
+#endif /* NETBSD15 */
+#endif /* NETBSD16 */
+#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   */
+
+#ifdef MINIX
+#ifdef MINIX2
+#define HERALD " Minix 2.0"
+#else
+#define HERALD " Minix 1.x"
+#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
+#define HERALD " Linux"
+#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 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 /* 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 " 32-bit Windows"
+#else /* NT */
+#define HERALD " 32-bit OS/2"
+#endif /* NT */
+#endif /* OS/2 */
+
+#ifndef HERALD
+#define HERALD " Unknown Version"
+#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 */
diff --git a/ckermit-8.0.211/ckuxla.c b/ckermit-8.0.211/ckuxla.c
new file mode 100644
index 0000000..eaf7976
--- /dev/null
+++ b/ckermit-8.0.211/ckuxla.c
@@ -0,0 +1,7446 @@
+#include "ckcsym.h"
+
+#include "ckcdeb.h"			/* Includes... */
+#include "ckcker.h"
+#include "ckucmd.h"
+#include "ckcxla.h"
+
+#ifdef NOXFER
+#define zdstuff(a)
+#endif /* NOXFER */
+
+#ifndef NOCSETS
+char *xlav = "Character Set Translation 8.0.042, 3 Jul 2000";
+
+/*  C K U X L A  */
+
+/*  C-Kermit tables and functions supporting character set translation.  */
+/*
+  Author: Frank da Cruz <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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.
+*/
+
+/* 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 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,
+    "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. */
+
+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 yet.
+  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-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 */
+#ifdef KANJI
+    "iso2022jp-kanji",    FC_JIS7,    0, /* Synonym for JIS-7 */
+#endif /* KANJI */
+    "italian",            FC_ITASCII, 0, /* 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,
+    "koi8",               FC_KOI8,    0, /* Old KOI-8 Cyrillic */
+    "koi8-cyrillic",      FC_KOI8,    CM_INV,
+    "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 */
+#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 */
+    "utf8",               FC_UTF8,    0, /* ISO 10646 / Unicode UTF-8 */
+#endif /* UNICODE */
+    "", 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, /* IBM CP437 */
+    "cp850",              FC_CP850,   0, /* IBM CP850 */
+#ifdef LATIN2
+    "cp852",              FC_CP852,   0, /* IBM 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 COMMENT
+#ifdef KANJI
+    "dec-kanji",          FC_JDEC,    0, /* Japanese DEC Kanji */
+#endif /* KANJI */
+#endif /* COMMENT */
+    "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 */
+    "italian",            FC_ITASCII, 0, /* Italian NRC */
+#ifdef COMMENT
+/* Kanji terminal character sets not implemented yet */
+#ifdef KANJI
+    "japanese-euc",       FC_JEUC,    0, /* Japanese EUC */
+    "jis7-kanji",         FC_JIS7,    0, /* Japanese JIS7 7bit code */
+#endif /* KANJI */
+#endif /* COMMENT */
+#ifdef CYRILLIC
+    "k",                  FC_KOI8,    CM_ABR|CM_INV,
+    "ko",                 FC_KOI8,    CM_ABR|CM_INV,
+    "koi",                FC_KOI8,    CM_ABR|CM_INV,
+    "koi8",               FC_KOI8,    0, /* Old KOI-8 Cyrillic */
+    "koi8-cyrillic",      FC_KOI8,    CM_INV,
+    "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 COMMENT
+/* Kanji terminal character sets not implemented yet. */
+#ifdef KANJI
+    "shift-jis-kanji",    FC_SHJIS,   0, /* Japanese Kanji Shift-JIS */
+#endif /* KANJI */
+#endif /* COMMENT */
+#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
+    "utf8",               FC_UTF8,    0, /* ISO 10646 / Unicode UTF-8 */
+#endif /* UNICODE */
+    "", 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.
+*/
+
+_PROTOTYP(static int jpnxas, (int, int[]) );
+_PROTOTYP(static int jpnxkt, (int, int[]) );
+_PROTOTYP(static int jpnxkn, (int[], int[]) );
+
+static int jpncnt;			/* Byte count for Japanese */
+static int jpnlst;			/* Last status (for JIS7) */
+
+static int
+jpnxas(a, obuf) int a; int obuf[]; { /* Translate ASCII to local file code */
+    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
+jpnxkt(a, obuf) int a; int obuf[]; {
+/* 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
+jpnxkn(ibuf, obuf) int ibuf[], obuf[]; {
+    /* 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 == '$') {		/* <ESC>$ */
+		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 == '(') {	/* <ESC>( == 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) {	/* <ESC><ESC> */
+		jpnpnt = jpnpnd = 0;	/* Reset pointers, stay in state */
+		if ((x = zminchar()) < 0) return(x);
+	    }
+	} else {			/* Not <ESC> - 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
+cs_is_nrc(x) int x; {
+#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
+cs_is_std(x) int x; {
+#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
+cs_size(x) int x; {
+#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
+setxlatype(tcs, fcs) int tcs, fcs; {
+#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
+initxlate(csin, csout) int csin, csout; {
+    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 */
diff --git a/ckermit-8.0.211/ckuxla.h b/ckermit-8.0.211/ckuxla.h
new file mode 100644
index 0000000..6dd3171
--- /dev/null
+++ b/ckermit-8.0.211/ckuxla.h
@@ -0,0 +1,118 @@
+/*
+  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 <fdc@columbia.edu>,
+  Columbia University Academic Information Systems, New York City.
+
+  Copyright (C) 1985, 2004,
+    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 */
diff --git a/ckermit-8.0.211/ckwart.c b/ckermit-8.0.211/ckwart.c
new file mode 100644
index 0000000..4ac88bf
--- /dev/null
+++ b/ckermit-8.0.211/ckwart.c
@@ -0,0 +1,746 @@
+#include "ckcsym.h"
+char *wartv = "Wart Version 2.14, 10 Nov 1999";
+
+#define CKWART_C
+
+#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, 2004,
+    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 <state names...>
+ *  %%
+ * <state> | <state,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 */
+
+_PROTOTYP( VOID setwstate, (int, trans) );
+_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
+setwstate(state,t) int state; trans t; {
+    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
+teststate(state,t) int state; trans t; {
+    int idx,msk;
+    idx = state/8;
+    msk = 0x80 >> (state % 8);
+    return(t->states[idx] & msk);
+}
+
+
+/*
+ * read input from here...
+ *
+ */
+
+trans
+rdinput(infp,outfp) FILE *infp,*outfp; {
+    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
+initial(infp,outfp) FILE *infp, *outfp; {
+    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
+isin(s,c) char *s; int c; {
+    for (; *s != '\0'; s++)
+      if (*s == (char) c) return(1);
+    return(0);
+}
+int
+isword(c) int c; {
+    static char special[] = ".%_-$@";	/* these are allowable */
+    return(isalnum(c) || isin(special,c));
+}
+
+/*
+ * read the next word into the given buffer.
+ *
+ */
+VOID
+rdword(fp,buf) FILE *fp; char *buf; {
+    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
+rdstates(fp,ofp) FILE *fp,*ofp; {
+    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
+newtrans() {
+    trans new;
+    int i;
+    new = (trans) malloc(sizeof (struct transx));
+    for (i=0; i<SBYTES; i++) new->states[i] = 0;
+    new->anyst = 0;
+    new->nxt = NULL;
+    return(new);
+}
+
+
+/*
+ * read all the rules.
+ *
+ */
+
+trans
+rdrules(fp,out) FILE *fp,*out; {
+    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
+statelist(fp,t) FILE *fp; trans t; {
+    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
+copyact(inp,outp,actno) FILE *inp,*outp; int actno; {
+    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
+faction(hd,state,chr) trans hd; int state,chr; {
+    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
+emptytbl() {
+    int i;
+    for (i=0; i<nstates*96; i++) tbl[i] = -1;
+}
+
+/*
+ * add the specified action to the output for the given state and chr.
+ *
+ */
+VOID
+addaction(act,state,chr) int act,state,chr; {
+    tbl[state*96 + chr] = act;
+}
+
+VOID
+writetbl(fp) FILE *fp; {
+    warray(fp,"tbl",tbl,96*(nstates+1),TBL_TYPE);
+}
+
+
+/*
+ * write an array to the output file, given its name and size.
+ *
+ */
+VOID
+warray(fp,nam,cont,siz,typ) FILE *fp; char *nam; int cont[],siz; char *typ; {
+    int i;
+    fprintf(fp,"%s %s[] = {\n",typ,nam);
+    for (i = 0; i < siz - 1; ) {
+	fprintf(fp," %2d,",cont[i]);
+	if ((++i % 16) == 0) putc('\n',fp);
+    }
+    fprintf(fp,"%2d\n};\n",cont[siz-1]);
+}
+
+#ifndef STRATUS
+#ifdef MAINTYPE
+/*
+  If you get complaints about "main: return type is not blah",
+  define MAINTYPE on the CC command line, e.g. "CFLAGS=-DMAINTYPE=int".
+*/
+MAINTYPE
+#else
+#ifdef CK_SCOV5
+int
+#else
+#ifdef __DECC
+#ifdef __ALPHA
+int
+#else
+VOID
+#endif /* __ALPHA */
+#else
+#ifdef STRATUS
+int
+#ifdef __GNUC__
+int
+#else
+/*
+  The default case should be int, not VOID, but it's been this way for
+  years (no doubt for a reason) and who knows how many builds would break
+  if I changed it.
+*/
+VOID
+#endif /* __GNUC__ */
+#endif /* STRATUS */
+#endif /* __DECC */
+#endif /* CK_SCOV5 */
+#endif /* MAINTYPE */
+#endif /* STRATUS */
+main(argc,argv) int argc; char **argv; {
+    trans head;
+    int state,c;
+    FILE *infile,*outfile;
+
+    if (argc > 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
+fatal(msg) char *msg; {
+    fprintf(stderr,"error in line %d: %s\n",lines,msg);
+    exit(BAD_EXIT);
+}
+
+VOID
+prolog(outfp) FILE *outfp; {
+    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
+epilogue(outfp) FILE *outfp; {
+    int c;
+    while ((c = *txt3++) != '\0') putc(c,outfp);
+}
+
+VOID
+copyrest(in,out) FILE *in,*out; {
+    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
+gettoken(fp) FILE *fp; {
+    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
+rdcmnt(fp) FILE *fp; {
+    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; i<HASHSIZE; i++) htab[i] = NULL;
+}
+
+/*
+ * compute the value of the hash for a symbol
+ *
+ */
+int
+hash(name) char *name; {
+    int sum;
+    for (sum = 0; *name != '\0'; name++) sum += (sum + *name);
+    sum %= HASHSIZE;			/* take sum mod hashsize */
+    if (sum < 0) sum += HASHSIZE;	/* disallow negative hash value */
+    return(sum);
+}
+
+/*
+ * make a private copy of a string...
+ *
+ */
+static char*
+copy(s) char *s; {
+    char *new;
+    new = (char *) malloc((int)strlen(s) + 1);
+    strcpy(new,s);
+    return(new);
+}
+
+/*
+ * enter state name into the hash table
+ *
+ */
+VOID
+enter(name,svalue) char *name; int svalue; {
+    int h;
+    struct sym *cur;
+    if (lkup(name) != -1) {
+	fprintf(stderr,"state \"%s\" appears twice...\n", name);
+	exit(BAD_EXIT);
+    }
+    h = hash(name);
+    cur = (struct sym *)malloc(sizeof (struct sym));
+    cur->name = 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
+lkup(name) char *name; {
+    struct sym *cur;
+    for (cur = htab[hash(name)]; cur != NULL; cur = cur->hnxt)
+      if (strcmp(cur->name,name) == 0) return(cur->val);
+    return(-1);
+}
diff --git a/ckermit-8.0.211/makefile b/ckermit-8.0.211/makefile
new file mode 100644
index 0000000..a810331
--- /dev/null
+++ b/ckermit-8.0.211/makefile
@@ -0,0 +1,7851 @@
+# makefile / Makefile / ckuker.mak / CKUKER.MAK
+#
+# Sat Apr 17 14:49:18 2004
+BUILDID=20040417
+#
+CKVER= "8.0.211"
+#
+# -- Makefile to build C-Kermit for UNIX and UNIX-like platforms --
+#
+# Copyright (C) 1985, 2004,
+#   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: Frank da Cruz, Columbia University
+# 612 West 115th Street, New York NY 10025-7799, USA
+# E-mail: fdc@columbia.edu
+# Fax:    +1 212 662-6442
+# Web:    http://www.columbia.edu/kermit/
+#
+# Contributions from many others.  Special thanks to Jeff Altman for the
+# secure-target entries, Peter Eichhorn, assyst GmbH, for the consolidated
+# HP-UX entries and the "uninstall" target, to Robert Lipe for the updated
+# and consolidated SCO UNIX / ODT / OSR5 entries, to Ric Anderson for the
+# IRIX 6.x entries.
+#
+# Most entries use the "xermit" target, which uses the select()-based CONNECT
+# module, ckucns.c.  The "wermit" target uses the older fork()-base CONNECT
+# module, ckucon.c, which has some drawbacks (but is more portable).  If your
+# entry still uses the "wermit" target, please try substituting the "xermit"
+# one and if it works, let us know (mailto:kermit-support@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.  Uppercase letters remove the danger, e.g. "# If you have..."
+#
+# WARNING: This is a huge makefile and it contains nested makes.  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.
+#
+# Certain UNIX variations have their own separate makefiles:
+#  . For 2.10 or 2.11 BSD on DEC PDP-11s, 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 for details.
+#
+#
+# DIRECTIONS
+#
+# 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 aix43", "make sys5r4",
+# "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 entries:
+#  'make install' is an installation script (read accompanying comments!).
+#  'make clean' removes intermediate and object files.
+#
+# 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 entries 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
+# entries 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.
+#
+# Fullscreen file transfer display support: If you are going to use C-Kermit
+# for establishing connections (dialed, network, etc), you can configure it to
+# produce a formatted file transfer display by including the curses library
+# and adding -DCK_CURSES to the CFLAGS for your option, and linking with the
+# appropriate libraries.  There are many examples below, usually ending in
+# "c", like sunos41c.  Also add -DCK_WREFRESH if your curses library includes
+# clearok() and wrefresh() functions (or remove -DNOWREFRESH if the linker
+# complains that it can't find these functions).
+#
+# Please report modifications, failures (preferably with fixes) or successes
+# to the author.
+#
+# SECURE TARGETS
+#  These are described after the next section.  Search for ******* below.
+#
+# TARGETS FOR DIFFERENT UNIX PLATFORMS AND VERSIONS:
+#
+# + Marks those that have been built successfully for C-Kermit 8.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.
+# --------------------------
+# ? 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 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 <dirent.h>, "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" (compile ckwart separately if necessary)
+# + 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" (maybe compile ckwart separately, or "touch ckcpro.c")
+# ? 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 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 <sys/file.h> 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 freebsd4"
+# + for FreeBSD 4.1, "make freebsd41"
+# + for FreeBSD 4.2, "make freebsd42"
+# + for FreeBSD 4.3, "make freebsd43"
+# + for FreeBSD 4.4, "make freebsd44"
+# + for FreeBSD 4.5, "make freebsd45"
+# + for FreeBSD 4.6, "make freebsd46"
+# + for FreeBSD 4.7, "make freebsd47"
+# + for FreeBSD 4.8, "make freebsd48"
+# + for FreeBSD 4.9, "make freebsd49"
+# ? for FreeBSD 5.0, "make freebsd50"
+# ? for FreeBSD 5.1, "make freebsd51"
+# ? 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"
+# + 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" or "make hpux0650c"
+# + 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 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, "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 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 Red Hat Linux 7.1 (and higher) 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 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.
+# + 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 on PowerMac (Mklinux DR3), "make mklinux".
+# + for Linux 1.2 and later, to build with egcs, "make linuxegcs".
+# + for Linux with no TCP/IP, "make linuxnotcp"
+# + for Linux with lcc compiler, no TCP/IP, "make linuxnotcp-lcc"
+# ? for Linux 1.0 or earlier, "make linux10", or (to remove TCP/IP)
+#     "make linuxnotcp".
+#     IMPORTANT: Read the comments that accompany the "linux:" entry.
+# ? 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 through 1.4.x on any architecture, "make netbsd"
+# + for NetBSD 1.5.0 and later, "make netbsd15"
+# + 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 <dirent.h>, "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).
+# ? 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 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, <dirent.h> 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 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"
+# + 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"
+# ? 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 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"
+# + for Tru-64 UNIX 4.0E, "make tru64-40e"
+# + for Tru-64 UNIX 4.0F, "make tru64-40f"
+# + for Tru-64 UNIX 4.0G, "make tru64-40g"
+# + for Tru-64 UNIX 5.0A, "make tru64-50a"
+# + for Tru-64 UNIX 5.1A, "make tru64-51a"
+# ? 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 where users can find it.
+#
+# 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 is 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.
+#
+# In OpenSSL builds add -ldl if you get unresolved references for
+# dlopen, dlclose, dlsym, and/or dlerror.
+#
+# The following symbols are used to specify library and header file locations
+# Redefine them to the values used on your system by:
+# . editing this file
+# . defining the values on the command line
+# . defining the values in the environment and use the -e option
+#
+prefix  = /usr/local
+srproot = $(prefix)
+sslroot = $(prefix)
+manroot = $(prefix)
+
+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
+#
+# aix41+krb5+krb4:                    IBM AIX 4.1 with Kerberos IV and V
+# aix43gcc+krb5+krb4:                 IBM AIX 4.3 built with gcc, ditto
+# aix43gcc+krb5+krb4+openssl:         Ditto, plus OpenSSL (SSL/TLS)
+# aix43gcc+openssl:                   IBM AIX 4.3 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...
+# linux+krb5:
+# 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:
+# openbsd30+ssl (includes 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:
+# uw7ssl
+#
+##############################################################################
+#
+# NOTES FOR V7 AND 2.X BSD (BASED ON VERSION 4E OF C-KERMIT, 1987):
+#
+# For Unix Version 7, several variables must be defined to the values
+# associated with your system.  BOOTNAME=/edition7 is the kernel image on
+# okstate's Perkin-Elmer 3230.  Others will probably be /unix.  PROCNAME=proc
+# is the name of the structure assigned to each process on okstate's system.
+# This may be "_proc" or some other variation.  See <sys/proc.h> for more
+# info on your systems name conventions.  NPROCNAME=nproc is the name of a
+# kernel variable that tells how many "proc" structures there are.  Again
+# this may be different on your system, but nproc will probably be somewhere.
+# The variable NPTYPE is the type of the nproc variable -- int, short, etc.
+# which can probably be gleaned from <sys/param.h>.  The definition of DIRECT
+# is a little more complicated.  If nlist() returns, for "proc" only, the
+# address of the array, then you should define DIRECT as it is below.  If
+# however, nlist() returns the address of a pointer to the array, then you
+# should give DIRECT a null definition (DIRECT= ).  The extern declaration in
+# <sys/proc.h> should clarify this for you.  If it is "extern struct proc
+# *proc", then you should NOT define DIRECT.  If it is "extern struct proc
+# proc[]", then you should probably define DIRECT as it is below.  See
+# ckuv7.hlp for further information.
+#
+# For 2.9 BSD, the makefile may use pcc rather than cc for compiles; that's
+# what the CC and CC2 definitions are for (the current version of the
+# makefile uses cc for both; this was tested in version 4E of C-Kermit and
+# worked OK on the DEC Pro 380, but all bets are off for version 5A).  2.9
+# support basically follows the 4.1 path.  Some 2.9 systems use "dir.h" for
+# the directory header file, others will need to change this to "ndir.h".
+#
+# The v7 and 2.9bsd versions assume I&D space on a PDP-11.  When building
+# C-Kermit for v7 on a PDP-11, you should probably add the -i option to the
+# link flags.  Without I&D space, overlays will be necessary (if available),
+# or code segment mapping (a`la Pro/Venix) if that's available.
+#
+# C-Kermit 5A (and 6.0?) can be built for 2.10 and 2.11BSD, using overlays,
+# but a separate makefile is used because this one is too big.
+#
+##############################################################################
+#
+# 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 )
+#
+###########################################################################
+#
+#  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
+
+###########################################################################
+# 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 solaris8 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
+
+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
+
+# 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
+#
+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 -p $$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 -p  $(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        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 "#!$(DESTDIR)$(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 "$(MANDIR)"; then\
+		if test -d $(MANDIR); then\
+			echo  "$(MANDIR) exists...";\
+		else\
+			echo "Creating $(MANDIR)...";\
+			mkdir $(MANDIR) || exit 1;\
+			chmod 755 $(MANDIR) || exit 1;\
+		fi;\
+		echo "Installing man page...";\
+		rm -f $(MANDIR)/kermit.$(MANEXT);\
+		cp    ckuker.nr $(MANDIR)/kermit.$(MANEXT) || exit 1;\
+		chmod 644       $(MANDIR)/kermit.$(MANEXT) || exit 1;\
+		echo 'set flag=f\nPrC Removing man pages' >&3;\
+		echo "RmF $(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 hpux1100, make aix43, make solaris8.
+	@echo Please read the comments at the beginning of the makefile.
+
+###########################################################################
+#
+# Dependencies Section:
+
+# Normal version
+
+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)
+
+# Version with CONNECT module that uses select() instead of fork()
+
+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
+
+ckclib.$(EXT): ckclib.c ckclib.h ckcdeb.h ckcasc.h ckcsym.h
+
+ckcpro.$(EXT): ckcpro.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckclib.h
+
+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
+
+ckcfn2.$(EXT): ckcfn2.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h \
+		ckuxla.h ckctel.h ckclib.h ckcnet.h ckcuni.h
+
+ckcfn3.$(EXT): ckcfn3.c ckcker.h ckcdeb.h ckcsym.h ckcasc.h ckcxla.h \
+		ckuxla.h ckclib.h ckcuni.h
+
+ckuxla.$(EXT): ckuxla.c ckcker.h ckcsym.h ckcdeb.h ckcxla.h ckuxla.h ckclib.h \
+		 ckcuni.h
+
+ckcuni.$(EXT): ckcuni.c ckcdeb.h ckcker.h ckucmd.h ckcuni.h ckcxla.h ckuxla.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
+
+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
+
+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
+
+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
+
+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
+
+ckuus6.$(EXT): ckuus6.c ckucmd.h ckcker.h ckuusr.h ckcdeb.h ckcasc.h ckcnet.h \
+		 ckcsym.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 ckcsym.h ckctel.h ckclib.h ckcuni.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
+
+ckuusy.$(EXT): ckuusy.c ckcker.h ckcdeb.h ckcasc.h ckcnet.h ckcsym.h ckctel.h \
+		 ckclib.h
+
+ckucmd.$(EXT): ckucmd.c ckcasc.h ckucmd.h ckcdeb.h ckcsym.h ckctel.h ckclib.h
+
+ckufio.$(EXT): ckufio.c ckcdeb.h ckuver.h ckcsym.h ckclib.h \
+		ckcxla.h ckuxla.h ckcuni.h
+
+ckutio.$(EXT): ckutio.c ckcdeb.h ckcnet.h ckuver.h ckcsym.h ckctel.h ckclib.h
+
+ckucon.$(EXT): ckucon.c ckcker.h ckcdeb.h ckcasc.h ckcnet.h ckcsym.h ckctel.h \
+		 ckclib.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
+
+ckcnet.$(EXT): ckcnet.c ckcdeb.h ckcker.h ckcnet.h ckcsym.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) $(LIBS)
+
+ckcmdb.$(EXT): ckcmdb.c ckcdeb.h ckcsym.h ckclib.h
+
+ckwart.$(EXT): ckwart.c
+
+ckudia.$(EXT): ckudia.c ckcker.h ckcdeb.h ckucmd.h ckcasc.h ckcsym.h ckcsig.h \
+		ckcnet.h ckctel.h ckclib.h
+
+ckuscr.$(EXT): ckuscr.c ckcker.h ckcdeb.h ckcasc.h ckcsym.h ckcsig.h \
+		ckcnet.h ckctel.h ckclib.h
+
+ckusig.$(EXT): ckusig.c ckcasc.h ckcdeb.h ckcker.h ckcnet.h ckuusr.h \
+		ckcsig.h ckctel.h ckclib.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
+
+ckupty.$(EXT): ckupty.c ckupty.h ckcdeb.h
+
+ckuath.$(EXT): ckuath.c ckcdeb.h ckucmd.h ckuath.h ckuat2.h ckctel.h \
+		 ckclib.h ckcnet.h
+
+ck_crp.$(EXT): ck_crp.c ckcdeb.h ckcnet.h ckuath.h ckclib.h
+
+ck_ssl.$(EXT): ck_ssl.c ckcdeb.h ckucmd.h ckuath.h ckuat2.h ckctel.h \
+		 ckclib.h ck_ssl.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 <dirent.h>.
+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 <signal.h> 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)
+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().
+freebsd4:
+	@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, as above but without the NONOSETBUF hack and with CK_NEWTERM.
+#This works with ncurses 5.1.
+freebsd41:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.1 with ncurses...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DFREEBSD41 -DUSE_UU_LOCK -DFNFLOAT \
+	-funsigned-char -DTPUTSARGTYPE=int -DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#Default FreeBSD make for C-Kermit 8.0...
+freebsd:
+	$(MAKE) "MAKE=$(MAKE)" CC=$(CC) CC2=$(CC2) \
+	KTARGET=$${KTARGET-$(@)} freebsd45
+
+#FreeBSD 4.2, like 4.1.
+freebsd42:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.2...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DFREEBSD41 -DFREEBSD42 -DUSE_UU_LOCK -DFNFLOAT \
+	-funsigned-char -DTPUTSARGTYPE=int -DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 4.3, like 4.2.
+freebsd43:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.3...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DUSE_UU_LOCK \
+	-DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int -DUSE_STRERROR $(KFLAGS) \
+	-O -pipe" "LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 4.4, like 4.3.
+freebsd44:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.4...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 \
+	-DUSE_UU_LOCK -DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int \
+	-DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 4.5, like 4.3 and 4.4.
+freebsd45:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.5...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DUSE_UU_LOCK -DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int \
+	-DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 -DFREEBSD45 \
+	-DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 4.6, like 4.5
+freebsd46:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.6...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DUSE_UU_LOCK -DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int \
+	-DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 -DFREEBSD45 \
+	-DFREEBSD46 -DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 4.7, like 4.6
+freebsd47:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.7...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DUSE_UU_LOCK -DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int \
+	-DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 -DFREEBSD45 \
+	-DFREEBSD46 -DFREEBSD47 -DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 4.8, like 4.7
+freebsd48:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.7...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DUSE_UU_LOCK -DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int \
+	-DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 -DFREEBSD45 \
+	-DFREEBSD46 -DFREEBSD47 -DFREEBSD48 \
+	-DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 4.9
+freebsd49:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.7...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DUSE_UU_LOCK -DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int \
+	-DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 -DFREEBSD45 \
+	-DFREEBSD46 -DFREEBSD47 -DFREEBSD48 -DFREEBSD49 \
+	-DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 5.0, like 4.6
+freebsd50:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 5.0 with ncurses...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DUSE_UU_LOCK -DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int \
+	-DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 -DFREEBSD45 \
+	-DFREEBSD46 -DFREEBSD50 -DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#FreeBSD 5.1
+freebsd51:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 5.0 with ncurses...'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DUSE_UU_LOCK -DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int \
+	-DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 -DFREEBSD45 \
+	-DFREEBSD46 -DFREEBSD50 -DFREEBSD51 \
+	-DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lutil -lm $(LIBS)"
+
+#Secure builds for FreeBSD...  gcc required.
+
+freebsd44+srp+openssl:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 4.3 with SRP,SSL...'
+	$(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DFREEBSD4 -DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 \
+	-DCK_AUTHENTICATION -DCK_SRP \
+	-DCK_ENCRYPTION -DCK_CAST -DCK_DES -DLIBDES -DCK_SSL \
+	-DCK_CURSES -DTCPSOCKET  \
+	$(SRPINC) $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+	"LIBS = $(SRPLIB) $(SSLLIB) \
+	-lncurses -ltermcap -lsrp -lssl -lkrypto -lcrypto \
+	-lcrypt "
+
+# The following fragmentary FreeBSD+SLL target was suggested, but it's not
+# clear which version of FreeBSD it applies to.
+#
+# ALL_TARGET=	xermit
+# MAKE_ARGS=	KTARGET=freebsd \
+#		CFLAGS="${CFLAGS} -DBSD44 -DCK_NCURSES -DCK_NEWTERM \
+#		-DTCPSOCKET -DNOCOTFMC -DFREEBSD4 -DUSE_UU_LOCK -DFNFLOAT \
+#		-funsigned-char -DTPUTSARGTYPE=int -DUSE_STRERROR -DCKHTTP \
+#		-DCK_SSL -DCK_AUTHENTICATION -DCK_ENCRYPTION -DCK_DES" \
+#		LIBS="-lssl -lcrypto -ldes -lncurses -lcrypt -lutil -lm"
+
+#FreeBSD 5.0 with OpenSSL 0.9.7.
+freebsd50+openssl:
+	@echo 'Making C-Kermit $(CKVER) for FreeBSD 5.0, ncurses, openssl'
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_NCURSES -DCK_NEWTERM -DTCPSOCKET -DNOCOTFMC \
+	-DCK_AUTHENTICATION -DCK_SSL $(SSLINC) -DZLIB \
+	-DFREEBSD4 -DUSE_UU_LOCK -DFNFLOAT -funsigned-char -DTPUTSARGTYPE=int \
+	-DFREEBSD41 -DFREEBSD42 -DFREEBSD43 -DFREEBSD44 -DFREEBSD45 \
+	-DFREEBSD46 -DFREEBSD50 -DUSE_STRERROR $(KFLAGS) -O -pipe" \
+	"LIBS= -lncurses -lcrypt -lssl -lcrypto -lutil -lm $(SSLLIB) $(LIBS)"
+
+#NetBSD - all versions - with curses, not ncurses.
+#Some builds seem to need KFLAGS=-DTPUTSFNTYPE=int, others don't.
+#(Only to get rid of a warning -- the binaries are identical.)
+netbsd:
+	@echo Making C-Kermit $(CKVER) for NetBSD with curses...
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DUSE_STRERROR -DTPUTSISVOID \
+	-DCK_DTRCD -DCK_DTRCTS -DTPUTSARGTYPE=int -DFNFLOAT $(KFLAGS) -O" \
+	"LIBS= -lcurses -lcrypt -lm $(LIBS)"
+
+#NetBSD 1.5.x in which the return type of the function pointer that is the
+#third argument of tputs() was changed from void to int...  The regular NetBSD
+#target builds OK here but this one eliminates the (harmless) warning.
+netbsd15:
+	@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 -DFNFLOAT $(KFLAGS) -O" \
+	"LIBS= -lcurses -lcrypt -lm $(LIBS)"
+
+#NetBSD 1.6 - like 1.5.x but with vanity banner saying 1.6.
+netbsd16:
+	@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 -DNETBSD16 \
+	-DCK_DTRCD -DCK_DTRCTS -DTPUTSARGTYPE=int -DFNFLOAT $(KFLAGS) -O" \
+	"LIBS= -lcurses -lcrypt -lm $(LIBS)"
+
+#NetBSD with ncurses requested explicitly rather than curses-which-is-ncurses
+netbsdn:
+	@echo Making C-Kermit $(CKVER) for NetBSD with ncurses...
+	$(MAKE) CC=$(CC) CC2=$(CC2) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD44 -DCK_CURSES -DTCPSOCKET -DNOCOTFMC -DCK_DTRCD \
+	-DCK_DTRCTS -DFNFLOAT -DUSE_STRERROR -DTPUTSISVOID -DTPUTSARGTYPE=int \
+	$(KFLAGS) -O" \
+	"LIBS= -L/usr/pkg/lib -lncurses -lcrypt -lm $(LIBS)"
+
+#OpenBSD - All versions.
+#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.
+openbsd:
+	@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 \
+	-DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR $(KFLAGS) -O" \
+	"LIBS= -lcurses -lutil -lm"
+
+#OpenBSD 3.0 or later includes OpenSSL
+#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.
+openbsd30+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 \
+	-DUSE_UU_LOCK -DFNFLOAT -DUSE_STRERROR -DCK_AUTHENTICATION \
+	-DCK_SSL $(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 <wjones@halcyon.com> 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 1.0 (Rhapsody, Darwin) -- TCP/IP but no curses.
+macosx10:
+	@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).
+macosx10c:
+	@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.
+macosx10nc:
+	@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.
+macosx102nc:
+	@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 entry.
+macosx10ncx:
+	@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.
+macosx103: 
+	@echo Making 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 \
+	$(KFLAGS) " "LIBS= -lncurses -lresolv $(LIBS)"
+
+macosx103nc:
+	$(MAKE) MAKE=$(MAKE) CC=$(CC) CC2=$(CC2) macosx103
+
+#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 $(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 $(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:
+	$(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS= -DBSD4 -DOSF -D_BSD -DTCPSOCKET -DCK_ANSIC -DSIG_V \
+	-DCK_CURSES -DCK_RTSCTS -DFNFLOAT $(KFLAGS)" \
+	"LNKFLAGS = -s" "LIBS = -lbsd -lcurses -ltermcap -lm"
+
+#DEC OSF/1 V1.0-1.3 on DECstation, VAX, Alpha, or PC.
+dec-osf:
+	$(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.1A...
+	$(MAKE) CC=$(CC) CC2=$(CC2) osf KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS= -DTRU64 -DOSF50 -DOSF51A -DOSF51B -DHDBUUCP \
+	-unsigned -std1 -O3 -Olimit 2400 $(KFLAGS)"
+
+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.
+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.
+#ckcpro.c compiled without optimization because it crashes the compiler.
+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 \
+	-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 <sys/termiox.h>, 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 <sys/termio.h>.
+#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 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 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 -- Must have CK_NEWTERM or echoing is lost after curses.
+# Add -bbigtoc in case ld fails with TOC overflow.
+aix42:
+	@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 $(KFLAGS)" \
+	"LNKFLAGS = -s" "LIBS=-lcurses -lm"
+
+#AIX 4.3 -- 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.
+aix43:
+	@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"
+
+aix44:
+	$(MAKE) aix42 "KFLAGS=-DAIX44 -qmaxmem=20000 $(KFLAGS)" \
+	KTARGET=$${KTARGET:-$(@)}
+
+aix45:
+	$(MAKE) aix42 "KFLAGS=-DAIX45 -qmaxmem=20000 $(KFLAGS)" \
+	KTARGET=$${KTARGET:-$(@)}
+
+aix50:
+	$(MAKE) aix42 "KFLAGS=-DAIX50 -qmaxmem=20000 $(KFLAGS)" \
+	KTARGET=$${KTARGET:-$(@)}
+
+aix51:
+	$(MAKE) aix42 "KFLAGS=-DAIX51 -qmaxmem=20000 $(KFLAGS)" \
+	KTARGET=$${KTARGET:-$(@)}
+
+aix52:
+	$(MAKE) aix42 "KFLAGS=-DAIX52 -qmaxmem=20000 $(KFLAGS)" \
+	KTARGET=$${KTARGET:-$(@)}
+
+aix53:
+	$(MAKE) aix42 "KFLAGS=-DAIX53 -qmaxmem=20000 $(KFLAGS)" \
+	KTARGET=$${KTARGET:-$(@)}
+
+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=<sys/types.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 " \'
+# Note: "xermit" means use the select() version of the CONNECT module.
+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"
+
+#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't 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.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.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 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 with gcc (32-bit)
+solaris8g:
+	$(MAKE) "MAKE=$(MAKE)" solaris2xg KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS=-DSOLARIS8 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+	"LIBS= -lpam"
+
+#Solaris 9 with gcc + OpenSSL + Shadow (32-bit)
+solaris9g+openssl+shadow+pam+zlib:
+	$(MAKE) "MAKE=$(MAKE)" solaris2xg+openssl+zlib+pam+shadow \
+	KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS=-DSOLARIS9 -DHDBUUCP -DDIRENT -DZLIB -DCK_PAM -DCK_SHADOW \
+	-DLIBDES $(KFLAGS)" "LIBS= -lpam -ldes425 -lz $(LIBS)"
+
+#Solaris 9 with gcc + OpenSSL + Kerberos 5 + Krb4 + Shadow (32-bit)
+solaris9g+krb5+krb4+openssl+shadow+pam+zlib:
+	$(MAKE) "MAKE=$(MAKE)" solaris2xg+krb5+krb4+openssl+shadow \
+	KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS=-DSOLARIS9 -DHDBUUCP -DDIRENT -DZLIB -DCK_PAM -DCK_SHADOW \
+	-DLIBDES $(KFLAGS)" "LIBS= -lpam -ldes425 -lz $(LIBS)"
+
+#Solaris 9 with gcc 3.1 (32-bit)
+solaris9g:
+	@echo 'Making C-Kermit $(CKVER) for Solaris 9 with gcc'
+	$(MAKE) "MAKE=$(MAKE)" CC="gcc -m32" CC2="gcc -m32" xermit \
+	KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS -DSOLARIS9 -DUSE_STRERROR \
+	-DSTERMIOX -DSELECT -DFNFLOAT -DCK_PAM -DCK_SHADOW -funsigned-char \
+	-DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \
+	"LIBS= -ltermlib -lsocket -lnsl -lm -lresolv -lpam"
+
+#Solaris 9 with gcc 3.1 (64-bit)
+#Peeking inside struct FILE at its members ist strengst verboten.
+solaris9g64:
+	@echo 'Making C-Kermit $(CKVER) for Solaris 9 with gcc'
+	$(MAKE) "MAKE=$(MAKE)" CC="gcc -m64" CC2="gcc -m64" xermit \
+	KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS = -g -O -Usun -DSVR4 -DSOLARIS 	-DSOLARIS9 -DNOARROWKEYS \
+	-DSTERMIOX -DSELECT -DFNFLOAT -DUSE_STRERROR -DCK_PAM -DCK_SHADOW \
+	-DCK_CURSES -DCK_NEWTERM -DDIRENT -DHDBUUCP -DTCPSOCKET $(KFLAGS)" \
+	"LIBS= -ltermlib -lsocket -lnsl -lm -lresolv -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 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 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"
+
+#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.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.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"
+
+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.6, SunPro compiler, curses, TCP/IP
+solaris26:
+	$(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS=-DSOLARIS26 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+	"LIBS= -lpam"
+
+#Solaris 7 (aka 2.7)
+solaris7:
+	$(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS=-DSOLARIS7 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+	"LIBS= -lpam"
+
+#Solaris 8
+solaris8:
+	$(MAKE) "MAKE=$(MAKE)" solaris25x KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS=-DSOLARIS8 -DCK_PAM -DCK_SHADOW $(KFLAGS)" \
+	"LIBS= -lpam"
+
+#Solaris 9
+solaris9:
+	$(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 \
+	-DSOLARIS9 -Dmalloc=dmalloc -Dfree=dfree -DMDEBUG \
+	-DCK_PAM -DCK_SHADOW -DUSE_STRERROR $(KFLAGS)" \
+	"LIBS= -lpam -ltermlib -lsocket -lnsl -lm -lresolv"
+
+#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.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"
+
+#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"
+
+#The following 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)
+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 $(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 <termiox.h>.
+#Has <termiox.h> 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 <termiox.h>.
+#Has <sys/termiox.h> 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 <termiox.h>.
+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 <termiox.h>.
+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 <sys/termiox.h>, 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 <sys/termiox.h>.
+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 <sys/termiox.h>, 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, <sys/termiox.h>, 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 <sys/termiox.h>, 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, <sys/termiox.h>, 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 <sys/termiox.h>
+#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 <sys/termiox.h>.
+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 <sys/termiox.h>.
+#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
+#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 \
+	-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:
+	@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 <sys/termiox.h>, 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 <sys/termiox.h>, 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 <termio.x> or <sys/termio.x>.
+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 <termio.x> or <sys/termio.x>, 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 <termio.x> or <sys/termio.x>, 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 <sys/termiox.h>, 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<n> 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<n> 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 ckudeb.h that make -DIRIX6x define all
+#lower IRIX6x values and IRIX51.
+irix6x:
+	@echo 'Includes fullscreen file display and Yellow Pages...'
+	@echo 'Add -mips<n> 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 -DCK_CURSES -DTCPSOCKET -DNOCOTFMC \
+	$(KFLAGS) -O" "LIBS= -lcurses -ltermcap -lcrypt"
+
+#Note the new Optimization option syntax for MIPSpro CC 7.2.1.2m.
+irix65:
+	@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 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:-$(@)}
+
+irix6x+krb5:
+	@echo 'Includes fullscreen file display and Yellow Pages...'
+	@echo 'Add -mips<n> 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-10]* entries. 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 there only since
+#HP-UX 8.0!
+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.
+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 $(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.
+hpux0500wintcp:
+	@MESSAGE1="with WIN/TCP but without any extra compiler optimization" \
+	$(MAKE) hpux0500 KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS = -DTCPSOCKET -DHPUX5WINTCP -DINADDRX -DNO_DNS_SRV -DNOMHHOST \
+	-DNOHADDRLIST -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 xermit target does not work with this one!
+#If you get compiler warnings like 'Switch table overflow' increase the '...'
+#value in '-Wc,-Nw...'!
+hpux0650:
+	@$(MAKE) hpux-header
+	@echo 'supporting: NO long filenames, NO network${MESSAGE2}.'
+
+	$(MAKE) KTARGET=$${KTARGET:-$(@)} \
+		ckuusr.$(EXT) ckuus3.$(EXT) ckuus4.$(EXT) ckuus5.$(EXT) \
+	        ckuus6.$(EXT) ckuxla.$(EXT) ckcpro.$(EXT) \
+	"CFLAGS = -DHPUX -DHPUX6 -DSIG_V -DNOSYSLOG -DNOSELECT -DFNFLOAT \
+	-DDCLGETCWD -DNOGETUSERSHELL -DNO_DNS_SRV -DNOLEARN $(KFLAGS) \
+	-Wc,-Nw260"
+
+	$(MAKE) wermit KTARGET=$${KTARGET:-$(@)} \
+	"CFLAGS = -DHPUX -DHPUX6 -DSIG_V -DNOSYSLOG -DNOSELECT -DFNFLOAT \
+	-DDCLGETCWD -DNOGETUSERSHELL -DNO_DNS_SRV -DNOLEARN $(KFLAGS) \
+	-Wc,-Nw260 $(OFLAGS)" "LNKFLAGS = -s" "LIBS = -lm $(LIBS)"
+
+#Exactly as above, plus curses:
+hpux0650c:
+	@MESSAGE2=", but with curses" \
+	$(MAKE) hpux0650 KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS= -DCK_CURSES $(KFLAGS)" \
+	"LIBS= -lcurses"
+
+#Exactly as above, plus curses + network:
+#(doesn't work -- HP-UX 6 lacks the FD_SET macros -- this can be addressed
+
+hpux0650tcpc:
+	@MESSAGE2=", but with curses and with tcp/ip" \
+	$(MAKE) hpux0650 KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS= -DCK_CURSES -DTCPSOCKET -DNOHADDRLIST $(KFLAGS)" \
+	"LIBS= -lcurses"
+
+#Exactly as hpux0650 but with compiler optimization:
+hpux0650o:
+	@MESSAGE1="with compiler optimization" \
+	$(MAKE) hpux0650 KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS= $(KFLAGS)" "OFLAGS = -O"
+
+#Exactly as hpux0650c but with compiler optimization:
+hpux0650oc:
+	@MESSAGE1="with compiler optimization" \
+	$(MAKE) hpux0650c KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS= $(KFLAGS)" "OFLAGS = -O"
+
+#Take this as startup entry for all 'none optimized' files under HP-UX 7.x!
+#Make sure we doesn't call it with the '-O' option because this will blow up
+#the compiler!
+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' increase the '...'
+#value in '-Wc,-Nw...'!
+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:
+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.
+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\\\" $(KFLAGS) \
+	-Wc,-Nw260"
+
+	$(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\\\" $(KFLAGS) \
+	-Wc,-Nw260 $(OFLAGS)" "LNKFLAGS = -s" "LIBS= -lm -lBSD -lcurses"
+
+#Exactly as above but with compiler optimization:
+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.
+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\\\" \
+	$(KFLAGS) -Wc,-Nw260"
+
+	$(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\\\" \
+	$(KFLAGS) -Wc,-Nw260 \
+	$(OFLAGS)" "LNKFLAGS = -s" "LIBS = -lm -lBSD $(LIBS)"
+
+#Exactly as above + curses.
+hpux0700lfnc:
+	@MESSAGE2=', curses' \
+	$(MAKE) hpux0700lfn KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS= -DCK_CURSES $(KFLAGS)" \
+	"LIBS= -lcurses"
+
+#Exactly as above hpux0700lfn but with compiler optimization:
+hpux0700olfn:
+	@MESSAGE1="with compiler optimization" \
+	$(MAKE) hpux0700lfn KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS= $(KFLAGS)" "OFLAGS = -O"
+
+#Exactly as above hpux0700lfnc but with compiler optimization:
+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.
+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 \
+	$(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 \
+	$(KFLAGS) $(OFLAGS)" "LNKFLAGS = -s" "LIBS = -lm -lBSD $(LIBS)"
+
+#Exactly as above hpux0800 + curses.
+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.
+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
+hpux0800o:
+	@MESSAGE1="with compiler optimization" \
+	$(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS = $(KFLAGS)" "OFLAGS = -O"
+
+#Exactly as above hpux0800 + curses and with compiler optimization.
+hpux0800oc:
+	@MESSAGE1="with compiler optimization" \
+	$(MAKE) hpux0800c KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS = $(KFLAGS)" "OFLAGS = -O" "LIBS = -lcurses"
+
+#Exactly as above hpux0800notcp but with compiler optimization
+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.
+hpux0800pa:
+	@MESSAGE1="with PA-RISC-specific optimization" \
+	$(MAKE) hpux0800 KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS = $(KFLAGS) +Obb1100"
+
+#As above, but with curses.
+hpux0800pac:
+	@MESSAGE1="with PA-RISC-specific optimization" \
+	$(MAKE) hpux0800c KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS = $(KFLAGS) +Obb1100"
+
+#As above, but compiled with GCC 2.3.3.
+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.
+hpux0900:
+	@MESSAGE1A='. Read hpux0900 entry comments if you have trouble.' \
+	$(MAKE) hpux-header
+	$(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 $(KFLAGS)" \
+	"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.
+# If optimization fails on some modules, you can add:
+#  +Obb<n>, +Olimit <n>, or +Onolimit, depending on your cc version,
+# where <n> 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").
+hpux0900o:
+	@MESSAGE1=$${MESSAGE1:-"with compiler optimization"} \
+	$(MAKE) hpux0900 KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS = $(KFLAGS) -Aa -DCK_ANSIC -D_HPUX_SOURCE +O2"
+
+# 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.
+hpux0900m68ko:
+	@MESSAGE1='without compiler optimization for ckcpro.$(EXT) ...' \
+	$(MAKE) hpux-header
+	$(MAKE) ckuusr.$(EXT) ckuus3.$(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"
+
+# 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 = $(KFLAGS) -DCK_ANSIC -funsigned-char -O2"
+
+#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  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.
+#
+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 ; \
+	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 \
+	$$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.
+#
+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) \
+		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+openssl:
+	$(MAKE) hpux1000t KTARGET=$${KTARGET:-$(@)}
+
+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 support 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).
+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) \
+	-Aa -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.
+#Do 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/...
+#Ditto for the Zlib location.
+#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+openssl:
+	@case "$(KTARGET)" in \
+	   *gcc+*) KENTRY=hpux1000gcc ;; \
+	   *)      KENTRY=hpux1000o ;; \
+	esac ; \
+	SSLINC=$${KSSLINC:-$(SSLINC)}; \
+	SSLLIB=$${KSSLLIB:-$(SSLLIB)}; \
+	MESSAGE1="and with OpenSSL $(MESSAGE1)" \
+	$(MAKE) $$KENTRY KTARGET=$${KTARGET:-$(@)} \
+	KFLAGS="-DCK_AUTHENTICATION -DCK_SSL -DOPENSSL_097 -DZLIB \
+	$$SSLINC $(KFLAGS)" \
+	KLIBS="$(KLIBS) \
+	$$SSLLIB -lssl -lcrypto \
+	-L/opt/zlib/lib -lz \
+	" 
+
+#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+openssl:
+	$(MAKE) hpux1000o+openssl KTARGET=$${KTARGET:-$(@)}
+
+# Same for HP-UX 11
+hpux1100o+openssl:
+	$(MAKE) hpux1000o+openssl KTARGET=$${KTARGET:-$(@)}
+
+hpux1100gcc+openssl:
+	$(MAKE) hpux1000gcc+openssl KTARGET=$${KTARGET:-$(@)}
+
+# HP-UX 11
+hpux1100:
+	$(MAKE) hpux1000 KTARGET=$${KTARGET:-$(@)}
+
+hpux1100o:
+	$(MAKE) hpux1000o KTARGET=$${KTARGET:-$(@)}
+
+hpux1100o+:
+	$(MAKE) hpux1000o+ KTARGET=$${KTARGET:-$(@)}
+
+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+openssl:
+	$(MAKE) hpux1000to+openssl KTARGET=$${KTARGET:-$(@)}
+
+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 ="
+
+# 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 ckubwr.txt about -DNOCOTFMC.  In fact, you really should read the
+# entire Linux section of ckubwr.txt.
+#
+# 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.
+
+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 = gcc" "CC2 = gcc" \
+	"CFLAGS = -O -DLINUX -pipe -funsigned-char -DFNFLOAT -DCK_POSIX_SIG \
+	-DCK_NEWTERM -DTCPSOCKET -DLINUXFSSTND -DNOCOTFMC -DPOSIX \
+	-DUSE_STRERROR $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" "LIBS = $(LIBS) -lm"
+
+linux-cross:
+	@echo 'Making C-Kermit $(CKVER) for Linux (cross-compiled)...'
+	gcc -o ckwart.o -c ckwart.c
+	gcc -o wart ckwart.o
+	$(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
+	"CC = $(CC)" "CC2 = $(CC)" "HOSTCC = gcc" \
+	"CFLAGS = -O -DLINUX -pipe -funsigned-char -DFNFLOAT -DCK_POSIX_SIG \
+	-DCK_NCURSES -DHAVE_PTMX \
+	-DCK_NEWTERM -DTCPSOCKET -DLINUXFSSTND -DNOCOTFMC -DPOSIX \
+	-DUSE_STRERROR $(NCURSES_CPPFLAGS) $(KFLAGS)" \
+	"LNKFLAGS = $(NCURSES_LDFLAGS) $(LNKFLAGS)" \
+	"LIBS = $(LIBS) -lncurses -lresolv -lcrypt -lm"
+
+# As above but with profiling
+linuxp:
+	$(MAKE) linuxa KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS) -pg" \
+	"LIBS=-pg -lcrypt -lresolv"
+
+#New primary Linux entry for C-Kermit 8.0, replacing big nested
+#if-then-else construction full of repeated clauses with a simpler scheme
+#for automatically detecting:
+# . Old versus new pty handling (new == glibc 2.1++)
+# . Presence or absence of librypt.a and <crypt.h>
+# . Presence or absence of libresolv.a
+#Unlike the previous scheme, this one is easily extended to include more tests.
+#Note: 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.  Warning: uses a temporary file in
+#the current directory.  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().
+linux:
+	@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 -f /usr/include/baudboy.h ; \
+	then HAVE_BAUDBOY='-DHAVE_BAUDBOY' ; \
+	else HAVE_BAUDBOY='' ; fi ; \
+	$(MAKE) KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS=-DCK_NCURSES -I/usr/include/ncurses \
+	$$HAVE_PTMX $$HAVE_BAUDBOY \
+	`if test -f /usr/include/crypt.h; then echo -DHAVE_CRYPT_H; fi` \
+	$(KFLAGS)" \
+	"LIBS=-lncurses \
+	`if test -f /usr/lib/libresolv.a || test -f /usr/lib/libresolv.so; \
+	then echo -lresolv; fi` \
+	`if test -f /usr/lib/libcrypt.a || test -f /usr/lib/libcrypt.so; \
+	then echo -lcrypt; fi`" \
+	linuxa
+
+# As above but for Linux systems that have no <sys/select.h>.
+linuxns:
+	$(MAKE) linux KTARGET=$${KTARGET:-$(@)} KFLAGS=-DNO_SYS_SELECT_H
+
+# As above, but forces use of curses rather than ncurses.
+# Add -ltermcap to LIBS if necessary.
+# Also watch out for libcurses and/or libtermcap having been moved.
+# In that case you might need something like:
+#  "LIBS = -L/usr/lib/curses -lcurses -L/usr/lib/termcap -ltermcap"
+
+linuxc:
+	@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 ; \
+	$(MAKE) KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS=-DCK_CURSES $$HAVE_PTMX \
+	`if test -f /usr/lib/libcrypt.a; then echo -DHAVE_CRYPTH; fi` \
+	$(KFLAGS)" \
+	"LIBS=-lcurses \
+	`if test -f /usr/lib/libresolv.a; then echo -lresolv; fi` \
+	`if test -f /usr/lib/libcrypt.a; then echo -lcrypt; fi`" \
+	linuxa
+
+# As above but with with no curses support, for example because you installed
+# the developer tools but did not install (n)curses.
+linuxnc:
+	@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 ; \
+	$(MAKE) KTARGET=$${KTARGET:-$(@)} \
+	"KFLAGS= $$HAVE_PTMX \
+	`if test -f /usr/lib/libcrypt.a; then echo -DHAVE_CRYPTH; fi` \
+	$(KFLAGS)" "LIBS= \
+	`if test -f /usr/lib/libresolv.a; then echo -lresolv; fi` \
+	`if test -f /usr/lib/libcrypt.a; then echo -lcrypt; fi`" \
+	linuxa
+
+#Sharp Zaurus SL-5500 - Linux based
+zsl5500:
+	@echo 'Making C-Kermit $(CKVER) for Sharp Zaurus SL-5500...'
+	@touch ckcpro.c
+	@touch wart
+	$(MAKE) linuxnc KTARGET=$${KTARGET:-$(@)} "KFLAGS=-DZSL5500" \
+	"CC = gcc" "CC2 = gcc"
+
+# A minimum-size version for Linux that does only scripting and
+# serial communication -- no networks, no file transfer.
+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 = "
+
+#Mklinux DR3 has horrible bug in <utmpbits.h> - 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
+
+
+# The remaining Linux entries are for special or customized builds.  They
+# have not been generalized 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 --
+# volunteers welcome.
+
+# If you get "Internal compiler error xxx, output pipe has been closed",
+# try removing -pipe.
+
+# Like "make linux" but built with egcs rather than gcc.
+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:
+	@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 Cygnus or MIT Kerberos 5 1.2.1 with K4 compatibility.
+#
+# Requires the Kerberos 1.2.1 be compiled with KRB4 compatibility.
+linux+krb5+krb4:
+	@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 -DKRB4 -DKRB524 \
+	-DCK_ENCRYPTION -DCK_DES -DCK_CURSES -DCK_POSIX_SIG \
+	-DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H $(K5INC) $(K5INC)/krb5 \
+	$(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+	"LIBS = $(K5LIB) -lncurses -ltermcap -lkrb4 -ldes425 -lkrb5 \
+	-lcom_err -lk5crypto -lcrypt -lgssapi_krb5 -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+shadow+pam:
+	@echo 'Making C-Kermit $(CKVER) for Linux on i386 with Shadow+PAM...'
+	$(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+	"CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+	-DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+	-DCK_SHADOW -DCK_PAM -DFNFLOAT \
+	$(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+	"LIBS = -lncurses -ltermcap -lcrypt -lpam -ldl -lm -lresolv"
+
+#Linux configured for SSL/TLS.
+#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+openssl:
+	@echo 'Making C-Kermit $(CKVER) for Linux on i386 with SSL/TLS...'
+	$(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+	"CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+	-DCK_AUTHENTICATION -DCK_SSL \
+	-DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+	-DFNFLOAT $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+	"LIBS= $(SSLLIB) \
+	-lncurses -ltermcap -lssl -lcrypto -lm -lresolv -lcrypt"
+
+#Linux configured for SSL/TLS and Shadow Passwords
+#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+openssl+shadow:
+	@echo 'Making C-Kermit $(CKVER) for Linux on i386 with SSL/TLS...'
+	$(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+	"CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+	-DCK_AUTHENTICATION -DCK_SSL \
+	-DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+	-DFNFLOAT -DCK_SHADOW $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+	"LIBS= $(SSLLIB) \
+	-lncurses -ltermcap -lssl -lcrypto -lm -lresolv -lcrypt"
+
+#Linux configured for SSL/TLS, ZLIB, PAM and Shadow Passwords
+#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+openssl+zlib+shadow+pam:
+	@echo 'Making C-Kermit $(CKVER) for Linux on i386 with SSL/TLS...'
+	$(MAKE) xermit KTARGET=$${KTARGET:-$(@)} "CC = gcc" "CC2 = gcc" \
+	"CFLAGS = -O -funsigned-char -pipe -DPOSIX -DLINUX -DNOCOTFMC \
+	-DCK_AUTHENTICATION -DCK_SSL -DCK_PAM -DZLIB \
+	-DCK_CURSES -DCK_POSIX_SIG -DTCPSOCKET -DLINUXFSSTND -DHAVE_CRYPT_H \
+	-DFNFLOAT -DCK_SHADOW $(SSLINC) $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" \
+	"LIBS= $(SSLLIB) \
+	-lncurses -ltermcap -lssl -lcrypto -lm -lresolv -lcrypt -lz -lpam -ldl"
+
+#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)"
+
+#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 \
+	-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"
+
+linuxnotcp:
+	$(MAKE) linux KTARGET=$${KTARGET:-$(@)} "KFLAGS = -DNONET $(KFLAGS)"
+
+# "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 <linux/serial.h>, 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 <curses.h>, but
+# this really should be <ncurses.h>.  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 <termios.h>" to the <termcap.h> 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"
+
+# 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.
+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,
+#<dirent.h> (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,
+#<dirent.h> (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.
+#<dirent.h> (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,
+#<dirent.h> (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 \
+	$(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 \
+	-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 \
+	$(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 <socket.h>
+sco32v500gcc:
+	@echo Using gcc...
+	$(MAKE) "MAKE=$(MAKE)" sco32v500CC=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 \
+	-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...
+	@echo If gcc crashes on ckwart.c then build it by hand:
+	@echo " gcc -o wart -DCK_SCOV5 ckwart.c"
+	$(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) " \
+
+#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 -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...
+	@echo If gcc crashes on ckwart.c then build it by hand:
+	@echo " gcc -o wart -DCK_SCOV5 ckwart.c"
+	$(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)"
+
+#Tandy 16/6000 with Xenix 3.0
+#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.
+#C-Kermit 7.0 does not build here; "too many defines".
+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"
+
+#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.
+# If you have trouble compiling or running wart, "touch wart".
+# If it still doesn't work, "touch ckcpro.c".
+# 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.
+# If you have trouble compiling or running wart, "touch wart" or
+# "touch ckcpro.c". 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 <sys/utime.h> 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 <sys/termiox.h>, 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 <dirent.h> 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 <ndir.h> = /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 <sys/ndir.h>
+#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 <dirent.h>.
+#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 <dirent.h>.
+#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) wart "CFLAGS= -DPROVX1 $(KFLAGS)" "LNKFLAGS= "
+	$(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...'
+	@touch ckcpro.c
+	$(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"
+
+# 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.
+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 -DNOCSETS \
+	-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+ '
+	cc -o wart ckwart.c
+	$(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 -DNOARROWKEYS \
+	-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"
+
+#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.  If you have trouble compiling or running
+# wart, "touch wart".  If that doesn't help, "touch ckcpro.c".
+# 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, new (as yet unreleased) ACK 2.0 beta C
+#compiler, which outputs .o object files, rather than .s.  But 'make' still
+#expects .s files, so must be patched to use .o.  Tested on Minix 1.5.10.
+minixnew:
+	@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"
+
+#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?'
diff --git a/ckermit.patches/ckermit-50.description b/ckermit.patches/ckermit-50.description
new file mode 100644
index 0000000..344772b
--- /dev/null
+++ b/ckermit.patches/ckermit-50.description
@@ -0,0 +1 @@
+This patch creates a target that allows c-kermit to be cross-compiled for a linux target on a linux host.
diff --git a/ckermit.patches/ckermit-50.patch b/ckermit.patches/ckermit-50.patch
new file mode 100644
index 0000000..cd698a9
--- /dev/null
+++ b/ckermit.patches/ckermit-50.patch
@@ -0,0 +1,48 @@
+--- a/makefile	2004-04-17 11:52:00.000000000 -0700
++++ b/makefile	2012-05-24 11:32:58.656618936 -0700
+@@ -966,7 +966,7 @@
+ 		else\
+ 			echo "Creating $(DESTDIR)...";\
+ 			DESTDIR=`echo $(DESTDIR) | sed 's!/*$$!!'`;\
+-			mkdir $$DESTDIR  || exit 1;\
++			mkdir -p $$DESTDIR  || exit 1;\
+ 		fi;\
+ 		chmod 755 $(DESTDIR) || exit 1;\
+ 	fi;\
+@@ -985,14 +985,14 @@
+ 		echo  "$(DESTDIR)$(BINDIR) exists...";\
+ 	else\
+ 		echo "Creating $(DESTDIR)$(BINDIR)/...";\
+-		mkdir     $(DESTDIR)$(BINDIR) || exit 1;\
++		mkdir -p  $(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\
++	ln -s        kermit\
+ 		     $(DESTDIR)$(BINDIR)/kermit-sshsub || exit 1;\
+ 	echo 'set flag=f\nPrC Removing binaries' >&3;\
+ 	echo "RmF $(DESTDIR)$(BINDIR)/kermit-sshsub" >&3;\
+@@ -5450,6 +5450,19 @@
+ 	-DCK_NEWTERM -DTCPSOCKET -DLINUXFSSTND -DNOCOTFMC -DPOSIX \
+ 	-DUSE_STRERROR $(KFLAGS)" "LNKFLAGS = $(LNKFLAGS)" "LIBS = $(LIBS) -lm"
+ 
++linux-cross:
++	@echo 'Making C-Kermit $(CKVER) for Linux (cross-compiled)...'
++	gcc -o ckwart.o -c ckwart.c
++	gcc -o wart ckwart.o
++	$(MAKE) xermit KTARGET=$${KTARGET:-$(@)} \
++	"CC = $(CC)" "CC2 = $(CC)" "HOSTCC = gcc" \
++	"CFLAGS = -O -DLINUX -pipe -funsigned-char -DFNFLOAT -DCK_POSIX_SIG \
++	-DCK_NCURSES -DHAVE_PTMX \
++	-DCK_NEWTERM -DTCPSOCKET -DLINUXFSSTND -DNOCOTFMC -DPOSIX \
++	-DUSE_STRERROR $(NCURSES_CPPFLAGS) $(KFLAGS)" \
++	"LNKFLAGS = $(NCURSES_LDFLAGS) $(LNKFLAGS)" \
++	"LIBS = $(LIBS) -lncurses -lresolv -lcrypt -lm"
++
+ # As above but with profiling
+ linuxp:
+ 	$(MAKE) linuxa KTARGET=$${KTARGET:-$(@)} "KFLAGS=$(KFLAGS) -pg" \
diff --git a/ckermit.tar.gz b/ckermit.tar.gz
new file mode 100644
index 0000000..259de77
--- /dev/null
+++ b/ckermit.tar.gz
Binary files differ
diff --git a/ckermit.url b/ckermit.url
new file mode 100644
index 0000000..ad51c6e
--- /dev/null
+++ b/ckermit.url
@@ -0,0 +1 @@
+ftp://kermit.columbia.edu/kermit/archives/cku211.tar.gz
diff --git a/ckermit.version b/ckermit.version
new file mode 100644
index 0000000..e7c9920
--- /dev/null
+++ b/ckermit.version
@@ -0,0 +1 @@
+8.0.211