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) */