applied 060_speeling.patch
authorIan Beckwith <ianb@erislabs.net>
Wed, 12 May 2010 00:21:53 +0000 (01:21 +0100)
committerIan Beckwith <ianb@erislabs.net>
Wed, 12 May 2010 00:21:53 +0000 (01:21 +0100)
.pc/060_speeling.patch/.timestamp [new file with mode: 0644]
.pc/060_speeling.patch/ckcftp.c [new file with mode: 0644]
.pc/060_speeling.patch/ckuus2.c [new file with mode: 0644]
.pc/applied-patches
ckcftp.c
ckuus2.c

diff --git a/.pc/060_speeling.patch/.timestamp b/.pc/060_speeling.patch/.timestamp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/.pc/060_speeling.patch/ckcftp.c b/.pc/060_speeling.patch/ckcftp.c
new file mode 100644 (file)
index 0000000..d8d9ddd
--- /dev/null
@@ -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/.pc/060_speeling.patch/ckuus2.c b/.pc/060_speeling.patch/ckuus2.c
new file mode 100644 (file)
index 0000000..1290763
--- /dev/null
@@ -0,0 +1,13838 @@
+#ifdef SSHTEST
+#define SSHBUILTIN
+#endif /* SSHTEST */
+
+/*  C K U U S 2  --  User interface strings & help text module for C-Kermit  */
+
+/*
+  Authors:
+    Frank da Cruz <fdc@columbia.edu>,
+      The Kermit Project, Columbia University, New York City
+    Jeffrey E Altman <jaltman@secure-endpoints.com>
+      Secure Endpoints Inc., New York City
+
+  Copyright (C) 1985, 2004,
+    Trustees of Columbia University in the City of New York.
+    All rights reserved.  See the C-Kermit COPYING.TXT file or the
+    copyright text in the ckcmai.c module for disclaimer and permissions.
+
+  This module contains HELP command and other long text strings.
+
+  IMPORTANT: Character string constants longer than about 250 are not portable.
+  Longer strings should be broken up into arrays of strings and accessed with
+  hmsga() rather than hmsg().
+*/
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcnet.h"
+#include "ckcasc.h"
+#include "ckcker.h"
+#include "ckuusr.h"
+#include "ckcxla.h"
+#ifdef OS2
+#ifdef NT
+#include <windows.h>
+#else /* not NT */
+#define INCL_KBD
+#ifdef OS2MOUSE
+#define INCL_MOU
+#endif /* OS2MOUSE */
+#define INCL_DOSMISC
+#define INCL_DOSDEVICES
+#include <os2.h>                /* This pulls in a whole load of stuff */
+#undef COMMENT
+#endif /* NT */
+#include "ckocon.h"
+#include "ckokvb.h"
+#include "ckokey.h"
+#endif /* OS2 */
+
+extern xx_strp xxstring;
+extern char * ccntab[];
+/*
+  hlptok contains the string for which the user requested help.  This is
+  useful for distinguishing synonyms, in case different help text is needed
+  depending on which synonym was given.
+*/
+extern char * hlptok;
+
+#ifndef NOIKSD
+    extern int inserver;
+#endif /* IKSD */
+
+#ifndef NOICP
+extern int cmflgs;
+
+#ifdef DCMDBUF
+extern char *cmdbuf, *atmbuf;
+#else
+extern char cmdbuf[], atmbuf[];
+#endif /* DCMDBUF */
+#endif /* NOICP */
+
+extern char *xarg0;
+extern int nrmt, nprm, dfloc, local, parity, escape;
+extern int turn, flow;
+extern int binary, quiet, keep;
+extern int success, xaskmore;
+#ifdef OS2
+extern int tt_rows[], tt_cols[];
+#else /* OS2 */
+extern int tt_rows, tt_cols;
+#endif /* OS2 */
+extern int cmd_rows, cmd_cols;
+
+extern long speed;
+extern char *dftty, *versio, *ckxsys;
+#ifndef NOHELP
+extern char *helpfile;
+#endif /* NOHELP */
+extern struct keytab prmtab[];
+#ifndef NOXFER
+extern struct keytab remcmd[];
+#endif /* NOXFER */
+
+#ifndef NOICP
+
+/*  Interactive help strings  */
+
+/* Top-level HELP text.  IMPORTANT: Also see tophlpi[] for IKSD. */
+
+static char *tophlp[] = {
+"Trustees of Columbia University in the City of New York.\n",
+
+#ifndef NOHELP
+"  Type EXIT    to exit.",
+#ifdef OS2
+"  Type INTRO   for a brief introduction to the Kermit Command screen.",
+"  Type LICENSE to see the Kermit 95 license.",
+#else
+"  Type INTRO   for a brief introduction to C-Kermit.",
+"  Type LICENSE to see the C-Kermit license.",
+#endif /* OS2 */
+"  Type HELP    followed by a command name for help about a specific command.",
+#ifndef NOPUSH
+#ifdef UNIX
+"  Type MANUAL  to access the C-Kermit manual page.",
+#else
+#ifdef VMS
+"  Type MANUAL  to access the C-Kermit help topic.",
+#else
+#ifdef OS2
+"  Type MANUAL  to access the K95 manual.",
+#else
+"  Type MANUAL  to access the C-Kermit manual.",
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* NOPUSH */
+"  Type NEWS    for news about new features.",
+"  Type SUPPORT to learn how to get technical support.",
+"  Press ?      (question mark) at the prompt, or anywhere within a command,",
+"               for a menu (context-sensitive help, menu on demand).",
+#else
+"Press ? for a list of commands; see documentation for detailed descriptions.",
+#endif /* NOHELP */
+
+#ifndef NOCMDL
+#ifndef NOHELP
+" ",
+"  Type HELP OPTIONS for help with command-line options.",
+#endif /* NOHELP */
+#endif /* NOCMDL */
+" ",
+#ifndef OS2
+#ifdef MAC
+"Documentation for Command Window: \"Using C-Kermit\" by Frank da Cruz and",
+"Christine M. Gianone, Digital Press, 1997, ISBN: 1-55558-164-1.  To order,",
+"call +1 212 854-3703 or +1 800 366-2665.",
+#else
+"DOCUMENTATION: \"Using C-Kermit\" by Frank da Cruz and Christine M. Gianone,",
+"2nd Edition, Digital Press / Butterworth-Heinemann 1997, ISBN 1-55558-164-1,",
+"plus supplements at http://www.columbia.edu/kermit/ckermit.html.",
+#endif /* MAC */
+#endif /* OS2 */
+#ifdef MAC
+" ",
+"Also see the Mac Kermit Doc and Bwr files on the Mac Kermit diskette.\n",
+#else
+#ifdef HPUX10
+" ",
+"See the files in /usr/share/lib/kermit/ for additional information.",
+#endif /* HPUX10 */
+#endif /* MAC */
+""
+};
+
+#ifndef NOIKSD
+static char *tophlpi[] = {              /* Top-level help for IKSD */
+
+"Trustees of Columbia University in the City of New York.\n",
+
+#ifndef NOHELP
+"  Type INTRO   for a brief introduction to Kermit commands.",
+"  Type VERSION for version and copyright information.",
+"  Type HELP    followed by a command name for help about a specific command.",
+"  Type SUPPORT to learn how to get technical support.",
+"  Type LOGOUT  (or EXIT) to log out.",
+"  Press ?      (question mark) at the prompt, or anywhere within a command,",
+"               for a menu (context-sensitive help, menu on demand).",
+#else
+"Press ? for a list of commands; see documentation for detailed descriptions.",
+#endif /* NOHELP */
+" ",
+"DOCUMENTATION: \"Using C-Kermit\" by Frank da Cruz and Christine M. Gianone,",
+"2nd Edition, Digital Press / Butterworth-Heinemann 1997, ISBN 1-55558-164-1.",
+"To order: +1 212 854-3703 or +1 800 366-2665.  More info at the Kermit",
+
+"Project website, http://www.columbia.edu/kermit/.",
+""
+};
+#endif /* NOIKSD */
+
+#ifndef NOHELP
+char *newstxt[] = {
+#ifdef OS2
+"Welcome to Kermit 95 2.1.3.  Major new features include:",
+#else
+"Welcome to C-Kermit 8.0.206.  Major new features include:",
+#endif /* OS2 */
+#ifdef NT
+#ifdef KUI
+" . Runs in GUI window",
+#else
+" . GUI version available",
+#endif /* KUI */
+#endif /* NT */
+#ifdef SSHBUILTIN
+" . New built-in SSH v1 and v2 clients",
+#endif /* SSHBUILTIN */
+#ifdef NEWFTP
+" . A new built-in FTP client",
+#endif /* NEWFTP */
+#ifndef NOHTTP
+" . A new HTTP 1.1 client",
+#endif /* NOHTTP */
+#ifdef TN_COMPORT
+" . Telnet Com Port Option for dialing from Telnet modem servers",
+#endif /* TN_COMPORT */
+" . File scanning for automatic text/binary determination",
+#ifdef CKLEARN
+#ifndef OS2
+" . Learned scripts",
+#endif /* OS2 */
+#endif /* CKLEARN */
+#ifndef NOSPL
+#ifndef NOSEXP
+" . LISP-like S-Expressions and natural floating-point arithmetic",
+#endif /* NOSEXP */
+" . Lots of script programming improvements",
+#endif /* NOSPL */
+" . Performance improvements and bug fixes",
+" ",
+"Documentation:",
+" 1. \"Using C-Kermit\", second edition (1997), current with C-Kermit 6.0.",
+" 2. http://www.columbia.edu/kermit/ckermit70.html",
+"    which documents the new features of C-Kermit 7.0.",
+" 3. http://www.columbia.edu/kermit/ckermit80.html",
+"    which documents the new features of C-Kermit 8.0.",
+" ",
+"If the release date shown by the VERSION command is long past, be sure to",
+"check with the Kermit Project to see if there have been updates.",
+""
+};
+#endif /* NOHELP */
+
+#ifndef NOHELP
+char *introtxt[] = {
+#ifdef OS2
+"Welcome to K-95, Kermit communications software for:",
+#else
+#ifdef UNIX
+#ifdef HPUX
+"Welcome to HP-UX C-Kermit communications software for:",
+#else
+"Welcome to UNIX C-Kermit communications software for:",
+#endif /* HPUX */
+#else
+#ifdef VMS
+"Welcome to VMS C-Kermit communications software for:",
+#else
+#ifdef VOS
+"Welcome to VOS C-Kermit communications software for:",
+#else
+#ifdef MAC
+"Welcome to Mac Kermit communications software for:",
+#else
+"Welcome to C-Kermit communications software for:",
+#endif /* MAC */
+#endif /* VOS */
+#endif /* VMS */
+#endif /* UNIX */
+#endif /* OS2 */
+#ifndef NOXFER
+" . Error-free and efficient file transfer",
+#endif /* NOXFER */
+#ifndef NOLOCAL
+#ifdef OS2
+" . VT320/220/102/100/52, ANSI, Wyse, Linux, Televideo, and other emulations",
+#else
+#ifdef MAC
+" . VT220 terminal emulation",
+#else
+" . Terminal connection",
+#endif /* MAC */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifndef NOSPL
+" . Script programming",
+#endif /* NOSPL */
+#ifndef NOICS
+" . International character set conversion",
+#endif /* NOICS */
+#ifndef NODIAL
+#ifndef NOSPL
+" . Numeric and alphanumeric paging",
+#endif /* NOSPL */
+#endif /* NODIAL */
+
+#ifndef NOLOCAL
+" ",
+"Supporting:",
+" . Serial connections, direct or dialed.",
+#ifndef NODIAL
+" . Automatic modem dialing",
+#endif /* NODIAL */
+#ifdef TCPSOCKET
+" . TCP/IP network connections:",
+#ifdef TNCODE
+"   - Telnet sessions",
+#endif /* TNCODE */
+#ifdef SSHBUILTIN
+"   - SSH v1 and v2 connections",
+#else
+#ifdef ANYSSH
+"   - SSH connections via external agent",
+#endif /* ANYSSH */
+#endif /* SSHBUILTIN */
+#ifdef RLOGCODE
+"   - Rlogin sessions",
+#endif /* RLOGCODE */
+#ifdef NEWFTP
+"   - FTP sessions",
+#endif /* NEWFTP */
+#ifdef CKHTTP
+"   - HTTP 1.1 sessions",
+#endif /* CKHTTP */
+#ifdef IKSD
+"   - Internet Kermit Service",
+#endif /* IKSD */
+#endif /* TCPSOCKET */
+#ifdef ANYX25
+" . X.25 network connections",
+#endif /* ANYX25 */
+#ifdef OS2
+#ifdef DECNET
+" . DECnet/PATHWORKS LAT Ethernet connections",
+#endif /* DECNET */
+#ifdef SUPERLAT
+" . Meridian Technologies' SuperLAT connections",
+#endif /* SUPERLAT */
+#ifdef NPIPE
+" . Named-pipe connections",
+#endif /* NPIPE */
+#ifdef CK_NETBIOS
+" . NETBIOS connections",
+#endif /* CK_NETBIOS */
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+" ",
+"While typing commands, you may use the following special characters:",
+" . DEL, RUBOUT, BACKSPACE, CTRL-H: Delete the most recent character typed.",
+" . CTRL-W:      Delete the most recent word typed.",
+" . CTRL-U:      Delete the current line.",
+" . CTRL-R:      Redisplay the current line.",
+
+#ifdef CK_RECALL
+#ifdef OS2
+" . Uparrow:     Command recall - go backwards in command recall buffer.",
+" . Downarrow:   Command recall - go forward in command recall buffer.",
+#ifndef NOIKSD
+"   (Note: Arrow keys can be used only on the PC's physical keyboard.)",
+#endif /* NOIKSD */
+#endif /* OS2 */
+" . CTRL-P:      Command recall - go backwards in command recall buffer.",
+" . CTRL-B:      Command recall - same as Ctrl-P.",
+" . CTRL-N:      Command recall - go forward in command recall buffer.",
+#endif /* CK_RECALL */
+
+" . ?            (question mark) Display a menu for the current command field."
+,
+" . ESC          (or TAB) Attempt to complete the current field.",
+" . \\            (backslash) include the following character literally",
+#ifndef NOSPL
+"                or introduce a backslash code, variable, or function.",
+#else
+"                or introduce a numeric backslash code.",
+#endif /* NOSPL */
+" ",
+
+"IMPORTANT: Since backslash (\\) is Kermit's command-line escape character,",
+"you must enter DOS, Windows, or OS/2 pathnames using either forward slash (/)"
+,
+"or double backslash (\\\\) as the directory separator in most contexts.",
+"Examples: C:/TMP/README.TXT, C:\\\\TMP\\\\README.TXT.",
+" ",
+
+"Command words other than filenames can be abbreviated in most contexts.",
+" ",
+
+"Basic commands:",
+"  EXIT          Exit from Kermit",
+"  HELP          Request general help",
+"  HELP command  Request help about the given command",
+"  TAKE          Execute commands from a file",
+"  TYPE          Display a file on your screen",
+"  ORIENTATION   Explains directory structure",
+" ",
+
+#ifndef NOXFER
+"Commands for file transfer:",
+"  SEND          Send files",
+"  RECEIVE       Receive files",
+"  GET           Get files from a Kermit server",
+#ifdef CK_RESEND
+"  RESEND        Recover an interrupted send",
+"  REGET         Recover an interrupted get from a server",
+#endif /* CK_RESEND */
+#ifndef NOSERVER
+"  SERVER        Be a Kermit server",
+#endif /* NOSERVER */
+" ",
+"File-transfer speed selection:",
+"  FAST          Use fast settings -- THIS IS THE DEFAULT",
+"  CAUTIOUS      Use slower, more cautious settings",
+"  ROBUST        Use extremely slow and cautious settings",
+" ",
+"File-transfer performance fine tuning:",
+"  SET RECEIVE PACKET-LENGTH  Kermit packet size",
+"  SET WINDOW                 Number of sliding window slots",
+"  SET PREFIXING              Amount of control-character prefixing",
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+" ",
+"To make a direct serial connection:",
+#ifdef OS2
+#ifdef NT
+#ifdef CK_TAPI
+"  SET PORT TAPI Select TAPI communication device",
+#endif /* CK_TAPI */
+"  SET PORT      Select serial communication device",
+#else
+"  SET PORT      Select serial communication port or server",
+#endif /* NT */
+#else
+"  SET LINE      Select serial communication device",
+#endif /* OS2 */
+"  SET SPEED     Select communication speed",
+"  SET PARITY    Communications parity (if necessary)",
+#ifdef CK_RTSCTS
+"  SET FLOW      Communications flow control, such as RTS/CTS",
+#else
+"  SET FLOW      Communications flow control, such as XON/XOFF",
+#endif /* CK_RTSCTS */
+"  CONNECT       Begin terminal connection",
+
+#ifndef NODIAL
+" ",
+"To dial out with a modem:",
+"  SET DIAL DIRECTORY     Specify dialing directory file (optional)",
+"  SET DIAL COUNTRY-CODE  Country you are dialing from (*)",
+"  SET DIAL AREA-CODE     Area-code you are dialing from (*)",
+"  LOOKUP                 Lookup entries in your dialing directory (*)",
+"  SET MODEM TYPE         Select modem type",
+#ifdef OS2
+#ifdef NT
+#ifdef CK_TAPI
+"  SET PORT TAPI          Select TAPI communication device",
+#endif /* CK_TAPI */
+"  SET PORT               Select serial communication device",
+#else
+"  SET PORT               Select serial communication port or server",
+#endif /* NT */
+#else
+"  SET LINE               Select serial communication device",
+#endif /* OS2 */
+"  SET SPEED              Select communication speed",
+"  SET PARITY             Communications parity (if necessary)",
+"  DIAL                   Dial the phone number",
+"  CONNECT                Begin terminal connection",
+" ",
+#ifdef OS2
+"Further info:   HELP DIAL, HELP SET MODEM, HELP SET PORT, HELP SET DIAL",
+#else
+"Further info:   HELP DIAL, HELP SET MODEM, HELP SET LINE, HELP SET DIAL",
+#endif /* OS2 */
+"(*) (For use with optional dialing directory)",
+#endif /* NODIAL */
+
+#ifdef NETCONN
+" ",
+"To make a network connection:",
+#ifndef NODIAL
+"  SET NETWORK DIRECTORY  Specify a network services directory (optional)",
+"  LOOKUP                 Lookup entries in your network directory",
+#endif /* NODIAL */
+"  SET NETWORK TYPE       Select network type (if more than one available)",
+"  SET HOST               Make a network connection but stay in command mode",
+"  CONNECT                Begin terminal connection",
+#ifdef TNCODE
+"  TELNET                 Select a Telnet host and CONNECT to it",
+#endif /* TNCODE */
+#ifdef RLOGCODE
+"  RLOGIN                 Select an Rlogin host and CONNECT to it",
+#endif /* RLOGCODE */
+#ifdef ANYSSH
+"  SSH [ OPEN ]           Select an SSH host and CONNECT to it",
+#endif /* ANYSSH */
+#ifdef NEWFTP
+"  FTP [ OPEN ]           Make an FTP connection",
+#endif /* NEWFTP */
+#ifdef CKHTTP
+"  HTTP OPEN              Make an HTTP connection",
+#endif /* CKHTTP */
+#endif /* NETCONN */
+
+#ifdef NT
+" ",
+"To return from the terminal window to the K-95> prompt:",
+#else
+#ifdef OS2
+" ",
+"To return from the terminal window to the K/2> prompt:",
+#else
+" ",
+"To return from a terminal connection to the C-Kermit prompt:",
+#endif /* OS2 */
+#endif /* NT */
+#ifdef OS2
+"  \
+Press the key or key-combination shown after \"Command:\" in the status line",
+"  (such as Alt-x) or type your escape character followed by the letter C.",
+#else
+"  Type your escape character followed by the letter C.",
+#endif /* OS2 */
+" ",
+"To display your escape character:",
+"  SHOW ESCAPE",
+" ",
+"To display other settings:",
+"  SHOW COMMUNICATIONS, SHOW TERMINAL, SHOW FILE, SHOW PROTOCOL, etc.",
+#else  /* !NOLOCAL */
+" ",
+"To display settings:",
+"  SHOW COMMUNICATIONS, SHOW FILE, SHOW PROTOCOL, etc.",
+#endif /* NOLOCAL */
+" ",
+#ifdef OS2
+"For a Kermit 95 tutorial, visit:",
+"  http://www.columbia.edu/kermit/k95tutor.html",
+" ",
+#endif /* OS2 */
+"For a C-Kermit tutorial, visit:",
+"  http://www.columbia.edu/kermit/ckututor.html",
+" ",
+"To learn about script programming and automation:",
+"  Read the manual, \"Using C-Kermit\".  For a brief tutorial, visit:",
+"  http://www.columbia.edu/kermit/ckscripts.html",
+" ",
+"For further information about a particular command, type HELP xxx,",
+"where xxx is the name of the command.  For documentation, news of new",
+"releases, and information about other Kermit software, contact:",
+" ",
+"  The Kermit Project         E-mail: kermit@columbia.edu",
+"  Columbia University        Web:    http://www.columbia.edu/kermit/",
+"  612 West 115th Street      Voice:  +1 (212) 854-3703",
+"  New York NY  10025-7799    Fax:    +1 (212) 662-6442",
+"  USA",
+""
+};
+
+static char * hmxymatch[] = {
+"SET MATCH { DOTFILE, FIFO } { ON, OFF }",
+"  Tells whether wildcards should match dotfiles (files whose names begin",
+"  with period) or UNIX FIFO special files.  MATCH FIFO default is OFF.",
+"  MATCH DOTFILE default is OFF in UNIX, ON elsewhere.",
+""
+};
+
+#ifdef OS2
+#ifdef KUI
+static char * hmxygui[] = {
+"SET GUI DIALOGS { ON, OFF }",
+"  ON means that popups, alerts, use GUI dialogs; OFF means to use",
+"  text-mode popups or prompts.  ON by default.",
+" ",
+"SET GUI FONT name size",
+"  Chooses the font and size.  Type \"set gui font ?\" to see the list of",
+"  choices.  The size can be a whole number or can contain a decimal point",
+"  and a fraction (which is rounded to the nearest half point).",
+" ",
+"SET GUI RGBCOLOR colorname redvalue greenvalue bluevalue",
+"  Specifies the red-green-blue mixture to be used to render the given",
+"  color name.  Type \"set gui rgbcolor\" to see a list of colornames.",
+"  the RGB values are whole numbers from 0 to 255.",
+" ",
+"SET GUI WINDOW POSITION x y",
+"  Moves the K95 window to the given X,Y coordinates, pixels from top left.",
+"  (Not yet implemented -- use command-line options to do this.)",
+" ",
+"SET GUI WINDOW RESIZE-MODE { CHANGE-DIMENSIONS, SCALE-FONT }",
+"  Default is CHANGE-DIMENSIONS.",
+"",
+"SET GUI WINDOW RUN-MODE { MAXIMIZE, MINIMIZE, RESTORE }",
+"  Changes the run mode state of the GUI window.",
+""
+};
+#endif /* KUI */
+#endif /* OS2 */
+
+#ifdef ANYSSH
+static char * hmxxssh[] = {
+#ifdef SSHBUILTIN
+"Syntax: SSH { ADD, AGENT, CLEAR, KEY, [ OPEN ], V2 } operands...",
+"  Performs an SSH-related action, depending on the keyword that follows:",
+" ",
+"SSH ADD LOCAL-PORT-FORWARD local-port host port",
+"  Adds a port forwarding triplet to the local port forwarding list.",
+"  The triplet specifies a local port to be forwarded and the hostname /",
+"  ip-address and port number to which the port should be forwarded from",
+"  the remote host.  Port forwarding is activated at connection",
+"  establishment and continues until the connection is terminated.",
+" ",
+"SSH ADD REMOTE-PORT-FORWARD remote-port host port",
+"  Adds a port forwarding triplet to the remote port forwarding list.",
+"  The triplet specifies a remote port to be forwarded and the",
+"  hostname/ip-address and port number to which the port should be",
+"  forwarded from the local machine.  Port forwarding is activated at",
+"  connection establishment and continues until the connection is",
+"  terminated.",
+" ",
+"SSH AGENT ADD [ identity-file ]",
+"  Adds the contents of the identity-file (if any) to the SSH AGENT",
+"  private key cache.  If no identity-file is specified, all files",
+"  specified with SET SSH IDENTITY-FILE are added to the cache.",
+" ",
+"SSH AGENT DELETE [ identity-file ]",
+"  Deletes the contents of the identity-file (if any) from the SSH AGENT",
+"  private key cache.  If no identity-file is specified, all files",
+"  specified with SET SSH IDENTITY-FILE are deleted from the cache.",
+" ",
+"SSH AGENT LIST [ /FINGERPRINT ]",
+"  Lists the contents of the SSH AGENT private key cache.  If /FINGERPRINT",
+"  is specified, the fingerprint of the private keys are displayed instead",
+"  of the keys.",
+" ",
+"SSH CLEAR LOCAL-PORT-FORWARD",
+"  Clears the local port forwarding list.",
+" ",
+"SSH CLEAR REMOTE-PORT-FORWARD",
+"  Clears the remote port forwarding list.",
+" ",
+"SSH KEY commands:",
+"  The SSH KEY commands create and manage public and private key pairs",
+"  (identities).  There are three forms of SSH keys.  Each key pair is",
+"  stored in its own set of files:",
+" ",
+"   Key Type      Private Key File           Public Key File",
+"    v1 RSA keys   \\v(appdata)ssh/identity   \\v(appdata)ssh/identity.pub",
+"    v2 RSA keys   \\v(appdata)ssh/id_rsa     \\v(appdata)ssh/id_rsa.pub",
+"    v2 DSA keys   \\v(appdata)ssh/id_dsa     \\v(appdata)ssh/id_dsa.pub",
+" ",
+"  Keys are stored using the OpenSSH keyfile format.  The private key",
+"  files can be (optionally) protected by specifying a passphrase.  A",
+"  passphrase is a longer version of a password.  English text provides",
+"  no more than 2 bits of key data per character.  56-bit keys can be",
+"  broken by a brute force attack in approximately 24 hours.  When used,",
+"  private key files should therefore be protected by a passphrase of at",
+"  least 40 characters (about 80 bits).",
+" ",
+"  To install a public key file on the host, you must transfer the file",
+"  to the host and append it to your \"authorized_keys\" file.  The file",
+"  permissions must be 600 (or equivalent).",
+" ",
+"SSH KEY CHANGE-PASSPHRASE [ /NEW-PASSPHRASE:passphrase",
+"      /OLD-PASSPHRASE:passphrase ] filename",
+"  This re-encrypts the specified private key file with a new passphrase.",
+"  The old passphrase is required.  If the passphrases (and filename) are",
+"  not provided Kermit prompts your for them.",
+" ",
+"SSH KEY CREATE [ /BITS:bits /PASSPHRASE:passphrase",
+"    /TYPE:{ V1-RSA, V2-DSA, V2-RSA } /V1-RSA-COMMENT:comment ] filename",
+"  This command creates a new private/public key pair.  The defaults are:",
+"  BITS:1024 and TYPE:V2-RSA.  The filename is the name of the private",
+"  key file.  The public key is created with the same name with .pub",
+"  appended to it.  If a filename is not specified Kermit prompts you for",
+"  it.  V1 RSA key files may have an optional comment, which is ignored",
+"  for other key types.",
+" ",
+"SSH KEY DISPLAY [ /FORMAT:{FINGERPRINT,IETF,OPENSSH,SSH.COM} ] filename",
+"  This command displays the contents of a public or private key file.",
+"  The default format is OPENSSH.",
+" ",
+"SSH KEY V1 SET-COMMENT filename comment",
+"  This command replaces the comment associated with a V1 RSA key file.",
+" ",
+"SSH [ OPEN ] host [ port ] [ /COMMAND:command /USER:username",
+"      /PASSWORD:pwd /VERSION:{ 1, 2 } /X11-FORWARDING:{ ON, OFF } ]",
+"  This command establishes a new connection using SSH version 1 or",
+"  version 2 protocol.  The connection is made to the specified host on",
+"  the SSH port (you can override the port by including a port name or",
+"  number after the host name).  Once the connection is established the",
+"  authentication negotiations begin.  If the authentication is accepted,",
+"  the local and remote port forwarding lists are used to establish the",
+"  desired connections.  If X11 Forwarding is active, this results in a",
+"  remote port forwarding between the X11 clients on the remote host and",
+"  X11 Server on the local machine.  If a /COMMAND is provided, the",
+"  command is executed on the remote host in place of your default shell.",
+" ",
+"  An example of a /COMMAND to execute C-Kermit in SERVER mode is:",
+"     SSH OPEN hostname /COMMAND:{kermit -x -l 0}",
+" ",
+"SSH V2 REKEY",
+"  Requests that an existing SSH V2 connection generate new session keys.",
+#else  /* SSHBUILTIN */
+"Syntax: SSH [ options ] <hostname> [ command ]",
+"  Makes an SSH connection using the external ssh program via the SET SSH",
+"  COMMAND string, which is \"ssh -e none\" by default.  Options for the",
+"  external ssh program may be included.  If the hostname is followed by a",
+"  command, the command is executed on the host instead of an interactive",
+"  shell.",
+#endif /* SSHBUILTIN */
+""
+};
+
+static char *hmxyssh[] = {
+#ifdef SSHBUILTIN
+"SET SSH AGENT-FORWARDING { ON, OFF }",
+"  If an authentication agent is in use, setting this value to ON",
+"  results in the connection to the agent being forwarded to the remote",
+"  computer.  The default is OFF.",
+" ",
+"SET SSH CHECK-HOST-IP { ON, OFF }",
+"  Specifies whether the remote host's ip-address should be checked",
+"  against the matching host key in the known_hosts file.  This can be",
+"  used to determine if the host key changed as a result of DNS spoofing.",
+"  The default is ON.",
+" ",
+"SET SSH COMPRESSION { ON, OFF }",
+"  Specifies whether compression will be used.  The default is ON.",
+" ",
+"SET SSH DYNAMIC-FORWARDING { ON, OFF }",
+"  Specifies whether Kermit is to act as a SOCKS4 service on port 1080",
+"  when connected to a remote host via SSH.  When Kermit acts as a SOCKS4",
+"  service, it accepts connection requests and forwards the connections",
+"  through the remote host.  The default is OFF.",
+" ",
+"SET SSH GATEWAY-PORTS { ON, OFF }",
+"  Specifies whether Kermit should act as a gateway for forwarded",
+"  connections received from the remote host.  The default is OFF.",
+" ",
+"SET SSH GSSAPI DELEGATE-CREDENTIALS { ON, OFF }",
+"  Specifies whether Kermit should delegate GSSAPI credentials to ",
+"  the remote host after authentication.  Delegating credentials allows",
+"  the credentials to be used from the remote host.  The default is OFF.",
+" ",
+"SET SSH HEARTBEAT-INTERVAL <seconds>",
+"  Specifies a number of seconds of idle time after which an IGNORE",
+"  message will be sent to the server.  This pulse is useful for",
+"  maintaining connections through HTTP Proxy servers and Network",
+"  Address Translators.  The default is OFF (0 seconds).",
+" ",
+"SET SSH IDENTITY-FILE filename [ filename [ ... ] ]",
+"  Specifies one or more files from which the user's authorization",
+"  identities (private keys) are to be read when using public key",
+"  authorization.  These are files used in addition to the default files:",
+" ",
+"    \\v(appdata)ssh/identity      V1 RSA",
+"    \\v(appdata)ssh/id_rsa        V2 RSA",
+"    \\v(appdata)ssh/id_dsa        V2 DSA",
+" ",
+"SET SSH KERBEROS4 TGT-PASSING { ON, OFF }",
+"  Specifies whether Kermit should forward Kerberos 4 TGTs to the host.",
+"  The default is OFF.",
+" ",
+"SET SSH KERBEROS5 TGT-PASSING { ON, OFF }",
+"  Specifies whether Kermit should forward Kerberos 5 TGTs to to the",
+"  host.  The default is OFF.",
+" ",
+"SET SSH PRIVILEGED-PORT { ON, OFF }",
+"  Specifies whether a privileged port (less than 1024) should be used",
+"  when connecting to the host.  Privileged ports are not required except",
+"  when using SSH V1 with Rhosts or RhostsRSA authorization.  The default",
+"  is OFF.",
+" ",
+"SET SSH QUIET { ON, OFF }",
+"  Specifies whether all messages generated in conjunction with SSH",
+"  protocols should be suppressed.  The default is OFF.",
+" ",
+"SET SSH STRICT-HOST-KEY-CHECK { ASK, ON, OFF }",
+"  Specifies how Kermit should behave if the the host key check fails.",
+"  When strict host key checking is OFF, the new host key is added to the",
+"  protocol-version-specific user-known-hosts-file.  When strict host key",
+"  checking is ON, the new host key is refused and the connection is",
+"  dropped.  When set to ASK, Kermit prompt you to say whether the new",
+"  host key should be accepted.  The default is ASK.",
+" ",
+"  Strict host key checking protects you against Trojan horse attacks.",
+"  It depends on you to maintain the contents of the known-hosts-file",
+"  with current and trusted host keys.",
+" ",
+"SET SSH USE-OPENSSH-CONFIG { ON, OFF }",
+"  Specifies whether Kermit should parse an OpenSSH configuration file",
+"  after applying Kermit's SET SSH commands.  The configuration file",
+"  would be located at \\v(home)ssh/ssh_config.  The default is OFF.",
+" ",
+"SET SSH V1 CIPHER { 3DES, BLOWFISH, DES }",
+"  Specifies which cipher should be used to protect SSH version 1",
+"  connections.  The default is 3DES.",
+" ",
+"SET SSH V1 GLOBAL-KNOWN-HOSTS-FILE filename",
+"  Specifies the location of the system-wide known-hosts file.  The",
+"  default is:",
+" ",
+"    \v(common)ssh_known_hosts",
+" ",
+"SET SSH V1 USER-KNOWN-HOSTS-FILE filename",
+"  Specifies the location of the user-known-hosts-file.  The default",
+"  location is:",
+" ",
+"    \\v(appdata)ssh/known_hosts",
+" ",
+"SET SSH V2 AUTHENTICATION { EXTERNAL-KEYX, GSSAPI, HOSTBASED, ",
+"    KEYBOARD-INTERACTIVE, PASSWORD, PUBKEY, SRP-GEX-SHA1 } [ ... ]",
+"  Specifies an ordered list of SSH version 2 authentication methods to",
+"  be used when connecting to the remote host.  The default list is:",
+" ",
+"    external-keyx gssapi hostbased publickey srp-gex-sha1 publickey",
+"    keyboard-interactive password none",
+" ",
+"SET SSH V2 AUTO-REKEY { ON, OFF }",
+"  Specifies whether Kermit automatically issues rekeying requests",
+"  once an hour when SSH version 2 in in use.  The default is ON.",
+" ",
+"SET SSH V2 CIPHERS { 3DES-CBC, AES128-CBC AES192-CBC AES256-CBC",
+"     ARCFOUR BLOWFISH-CBC CAST128-CBC RIJNDAEL128-CBC RIJNDAEL192-CBC",
+"     RIJNDAEL256-CBC }",
+"  Specifies an ordered list of SSH version ciphers to be used to encrypt",
+"  the established connection.  The default list is:",
+" ",
+"    aes128-cbc 3des-cbc blowfish-cbc cast128-cbc arcfour aes192-cbc",
+"    aes256-cbc",
+" ",
+"  \"rijndael\" is an alias for \"aes\".",
+" ",
+"SET SSH V2 GLOBAL-KNOWN-HOSTS-FILE filename",
+"  Specifies the location of the system-wide known-hosts file.  The default",
+"  location is:",
+" ",
+"    \\v(common)ssh/known_hosts2",
+" ",
+"SET SSH V2 HOSTKEY-ALGORITHMS { SSH-DSS, SSH-RSA }",
+"  Specifies an ordered list of hostkey algorithms to be used to verify",
+"  the identity of the host.  The default list is",
+" ",
+"    ssh-rsa ssh-dss",
+" ",
+"SET SSH V2 MACS { HMAC-MD5 HMAC-MD5-96 HMAC-RIPEMD160 HMAC-SHA1",
+"     HMAC-SHA1-96 }",
+"  Specifies an ordered list of Message Authentication Code algorithms to",
+"  be used for integrity  protection of the established connection.  The",
+"  default list is:",
+" ",
+"    hmac-md5 hmac-sha1 hmac-ripemd160 hmac-sha1-96 hmac-md5-96",
+" ",
+"SET SSH V2 USER-KNOWN-HOSTS-FILE filename",
+"  Specifies the location of the user-known-hosts file.  The default",
+"  location is:",
+" ",
+"    \\v(appdata)ssh/known_hosts2",
+" ",
+"SET SSH VERBOSE level",
+"  Specifies how many messages should be generated by the OpenSSH engine.",
+"  The level can range from 0 to 7.  The default value is 2.",
+" ",
+"SET SSH VERSION { 1, 2, AUTOMATIC }",
+"  Specifies which SSH version should be negotiated.  The default is",
+"  AUTOMATIC which means use version 2 if supported; otherwise to fall",
+"  back to version 1.",
+" ",
+"SET SSH X11-FORWARDING { ON, OFF }",
+"  Specifies whether X Windows System Data is to be forwarded across the",
+"  established SSH connection.  The default is OFF.  When ON, the DISPLAY",
+"  value is either set using the SET TELNET ENV DISPLAY command or read",
+"  from the DISPLAY environment variable.",
+" ",
+"SET SSH XAUTH-LOCATION filename",
+"  Specifies the location of the xauth executable (if provided with the",
+"  X11 Server software.)",
+#else  /* SSHBUILTIN */
+"Syntax: SET SSH COMMAND command",
+"  Specifies the external command to be used to make an SSH connection.",
+"  By default it is \"ssh -e none\" (ssh with no escape character).",
+#endif /* SSHBUILTIN */
+""
+};
+#endif /* ANYSSH */
+
+#ifdef NEWFTP
+static char *hmxygpr[] = {
+"Syntax: SET GET-PUT-REMOTE { AUTO, FTP, KERMIT}",
+"  Tells Kermit whether GET, PUT, and REMOTE commands should be directed",
+"  at a Kermit server or an FTP server.  The default is AUTO, meaning that",
+"  if you have only one active connection, the appropriate action is taken",
+"  when you give a GET, PUT, or REMOTE command.  SET GET-PUT-REMOTE FTP forces"
+,
+"  Kermit to treat GET, PUT, and REMOTE as FTP client commands; setting this",
+"  to KERMIT forces these commands to be treated as Kermit client commands.",
+"  NOTE: PUT includes SEND, MPUT, MSEND, and all other similar commands.",
+"  Also see HELP REMOTE, HELP SET LOCUS, HELP FTP.",
+""
+};
+#endif /* NEWFTP */
+
+#ifdef LOCUS
+static char *hmxylocus[] = {
+#ifdef KUI
+"Syntax: SET LOCUS { ASK, AUTO, LOCAL, REMOTE }",
+#else
+"Syntax: SET LOCUS { AUTO, LOCAL, REMOTE }",
+#endif /* KUI */
+"  Specifies whether unprefixed file management commands should operate",
+"  locally or (when there is a connection to a remote FTP or Kermit",
+"  server) sent to the server.  The affected commands are: CD (CWD), PWD,",
+"  CDUP, DIRECTORY, DELETE, RENAME, MKDIR, and RMDIR.  To force any of",
+"  these commands to be executed locally, give it an L-prefix: LCD, LDIR,",
+"  etc.  To force remote execution, use the R-prefix: RCD, RDIR, and so",
+"  on.  SHOW COMMAND shows the current Locus.",
+" ",
+"  By default, the Locus for file management commands is switched",
+"  automatically whenever you make or close a connection: if you make an",
+"  FTP connection, the Locus becomes REMOTE; if you close an FTP connection",
+"  or make any other kind of connection, the Locus becomes LOCAL.",
+#ifdef KUI
+" ",
+"  There are two kinds of automatic switching: ASK (the default) which",
+"  asks you if it's OK to switch, and AUTO, which switches without asking.",
+#endif /* KUI */
+" ",
+"  If you give a SET LOCUS LOCAL or SET LOCUS REMOTE command, this sets",
+"  the locus as indicated and disables automatic switching.",
+#ifdef KUI
+"  SET LOCUS AUTO or SET LOCUS ASK restores automatic switching.",
+"  You can also change Locus switching and behavior in the Actions menu.",
+#else
+"  SET LOCUS AUTO restores automatic switching.",
+#endif /* KUI */
+"",
+};
+#endif /* LOCUS */
+
+static char *hmxxtak[] = {
+"Syntax: TAKE filename [ arguments ]",
+"  Tells Kermit to execute commands from the named file.  Optional argument",
+"  words, are automatically assigned to the macro argument variables \\%1",
+"  through \\%9.  Kermit command files may themselves contain TAKE commands,",
+"  up to any reasonable depth of nesting.",
+""
+};
+
+#ifdef TCPSOCKET
+static char *hmxxfirew[] = {
+#ifdef OS2
+"Firewall Traversal in Kermit 95",
+#else
+"Firewall Traversal in C-Kermit",
+#endif
+" ",
+#ifndef NEWFTP
+#ifndef CKHTTP
+#ifndef CK_SOCKS
+#define NOFIREWALL
+#endif
+#endif
+#endif
+#ifdef NOFIREWALL
+"This version of Kermit was built with no support for firewall traversal",
+"protocols.  Kermit can be built with support for HTTP Proxy Servers,",
+"SOCKS authorized firewall traversal, and FTP Passive connection modes.",
+" ",
+#else /* NOFIREWALL */
+#ifdef CKHTTP
+"The simplist form of firewall traversal is the HTTP CONNECT command. The",
+"CONNECT command was implemented to allow a public web server which usually",
+"resides on the boundary between the public and private networks to forward",
+"HTTP requests from clients on the private network to public web sites.  To",
+"allow secure web connections, the HTTP CONNECT command authenticates the",
+"client with a username/password and then establishes a tunnel to the",
+"desired host.",
+
+" ",
+
+"Web servers that support the CONNECT command can be configured to allow",
+"outbound connections for authenticated users to any TCP/IP hostname-port",
+"combination accessible to the Web server.  HTTP CONNECT can be used only",
+"with TCP-based protocols.  Protocols such as Kerberos authentication that",
+"use UDP/IP cannot be tunneled using HTTP CONNECT.",
+
+" ",
+
+"SET TCP HTTP-PROXY [switches] [<hostname or ip-address>[:<port>]]",
+"  If a hostname or ip-address is specified, Kermit uses the given",
+"  proxy server when attempting outgoing TCP connections.  If no hostnamer",
+"  or ip-address is specified, any previously specified Proxy server is",
+"  removed.  If no port number is specified, the \"http\" service is used.",
+"  [switches] can be one or more of:",
+"     /AGENT:<agent> /USER:<user> /PASSWORD:<password>",
+"  Switch parameters are used when connecting to the proxy server and",
+"  override any other values associated with the connection.",
+" ",
+
+#endif /* CKHTTP */
+#ifdef CK_SOCKS
+
+"In the early 1990s as firewalls were becoming prevalent, David Koblas",
+"developed the SOCKS protocol for TCP/IP firewall traversal.  Two versions",
+"of SOCKS are currently in use: Version 4.2 lets TCP/IP client applications",
+"traverse firewalls, similar to HTTP CONNECT, except that the SOCKS client",
+"is aware of the public source IP address and port, which can be used within",
+"the application protocol to assist in securing the connection (e.g. FTP",
+"sessions secured with GSSAPI Kerberos 5).",
+
+" ",
+
+"In 1995 the IETF issued SOCKS Protocol Version 5 (RFC 1928), which is",
+"significantly more general than version 4.  Besides supporting client-",
+"to-server TCP/IP connections, it also includes:",
+
+" ",
+" . Authenticated firewall traversal of UDP/IP packets.",
+" . Authenticated binding of incoming public ports on the firewall.",
+" ",
+
+"This lets a service on the private network offer public services.  It also",
+"lets client applications like FTP establish a temporary public presence",
+"that can be used by the FTP server to create a data channel.  By allowing",
+"the client to bind to a public port on the firewall and be aware of the",
+"public address, SOCKS 5 lets the application protocol communicate this",
+"information to the server.",
+
+" ",
+
+#ifdef OS2
+#ifdef NT
+"Kermit 95 supports SOCKS 4.2.  The SOCKS Server is specified with:",
+" ",
+"  SET TCP SOCKS-SERVER hostname/ip-address",
+" ",
+"The SOCKS.CONF file is found by examining the ETC environment variable;",
+"searching in \\WINDOWS on Windows 95/98/ME; or the",
+"\\WINDOWS\\SYSTEM\\DRIVERS\\ETC directory on NT\\2000\\XP systems.",
+
+#else /* NT */
+
+"Kermit/2 provides support for SOCKS 4.2 servers when using IBM TCP/IP 2.0,",
+"IBM OS/2 WARP, or a compatible protocol stack. SOCKS is one popular means",
+"of implementing a firewall between a private network and the Internet.",
+" ",
+"Kermit/2 shares the same SOCKS environment variables as IBM Gopher. It also",
+"supports the use of local SOCKS configuration files.",
+" ",
+"To specify the default SOCKS Server, add SET SOCKS_SERVER= to your",
+"CONFIG.SYS file.",
+" ",
+"If you must use a SOCKS Distributed Name Server, add SET SOCKS_NS= to your",
+"CONFIG.SYS file.",
+" ",
+
+"If you must use a specific with your SOCKS server, be sure to add SET USER=",
+"to your CONFIG.SYS file. Otherwise, \"os2user\" is used by default.",
+
+" ",
+
+"The SOCKS configuration file must be placed in the directory pointed to by",
+"the ETC environment variable as declared in your CONFIG.SYS file. The name",
+"should be SOCKS.CONF. On a FAT file system, use SOCKS.CNF.",
+
+" ",
+"The format of the lines in the SOCKS configuration file are as follows:",
+" ",
+" . # comments",
+" . deny [*=userlist] dst_addr dst_mask [op port]",
+" . direct [*=userlist] dst_addr dst_mask [op port]",
+" . sockd [@=serverlist] [*=userlist] dst_addr dst_mask [op port]",
+" ",
+
+"op must be one of 'eq', 'neq', 'lt', 'gt', 'le', or 'ge'. dst_addr,",
+"dst_mask, and port may be either numeric or name equivalents.",
+
+" ",
+
+"Kermit/2 ignores the [*=userlist] and [@=serverlist] fields. Matches are",
+"determined on a first match not a best match basis. Addresses for which no",
+"match is found default to \"sockd\".",
+
+" ",
+
+"For completeness: Fields in square brackets are optional. The optional",
+"@=serverlist field with a 'sockd' line specifies the list of SOCKS servers",
+"the client should try (in the given order) instead of the default SOCKS",
+"server. If the @=serverlist part is omitted, then the default SOCKS server",
+"is used.  Commas are used in the userlist and serverlist as separators, no",
+"white spaces are allowed.",
+
+#endif /* NT */
+
+" ",
+
+#else /* OS2 */
+#ifdef CK_SOCKS5
+"This version of C-Kermit supports SOCKS version 5.",
+#else /* CK_SOCKS5 */
+"This version of C-Kermit supports SOCKS version 4.",
+#endif /* CK_SOCKS5 */
+
+"See the man page (or other system documentation) for information on",
+"configuring the SOCKS library via the /etc/socks.conf file.",
+
+#endif /* OS2 */
+" ",
+#endif /* CK_SOCKS */
+
+#ifdef NEWFTP
+
+"FTP is one of the few well-known Internet services that requires",
+"multiple connections.  As described above, FTP originally required the",
+"server to establish the data connection to the client using a destination",
+"address and port provided by the client.  This doesn't work with port",
+"filtering firewalls.",
+
+" ",
+
+"Later, FTP protocol added a \"passive\" mode, in which connections for",
+"the data channels are created in the reverse direction.  Instead of the",
+"server establishing a connection to the client, the client makes a second",
+"connection with the server as the destination.  This works just fine as",
+"long as the client is behind the firewall and the server is in public",
+"address space.  If the server is behind a firewall then the traditional",
+"active mode must be used.  If both the client and server are behind their",
+"own port filtering firewalls then data channels cannot be established.",
+
+" ",
+
+"In Kermit's FTP client, passive mode is controlled with the command:",
+
+" ",
+"  SET FTP PASSIVE-MODE { ON, OFF }",
+" ",
+
+"The default is ON, meaning to use passive mode.",
+
+#endif /* NEWFTP */
+#endif /* NOFIREWALL */
+
+""
+};
+#endif /* TCPSOCKET */
+
+static char *hmxxsave[] = {
+"Syntax: SAVE item filename { NEW, APPEND }",
+"  Saves the requested material in the given file.  A new file is created",
+"  by default; include APPEND at the end of the command to append to an",
+"  existing file.  Items:",
+#ifndef NOSETKEY
+"    KEYMAP               Saves the current key settings.",
+#endif /* NOSETKEY */
+#ifdef CK_RECALL
+"    COMMAND HISTORY      Saves the current command recall (history) buffer",
+#endif /* CK_RECALL */
+#ifdef OS2
+"    COMMAND SCROLLBACK   Saves the current command-screen scrollback buffer",
+"    TERMINAL SCROLLBACK  Saves the current terminal-screen scrollback buffer",
+#endif /* OS2 */
+""
+};
+
+#ifdef CKROOT
+static char *hmxxchroot[] = {
+"Syntax: SET ROOT directoryname",
+"  Sets the root for file access to the given directory and disables access",
+"  to system and shell commands and external programs.  Once this command",
+"  is given, no files or directories outside the tree rooted by the given",
+"  directory can be opened, read, listed, deleted, renamed, or accessed in",
+"  any other way.  This command can not be undone by a subsequent SET ROOT",
+"  command.  Primarily for use with server mode, to restrict access of",
+"  clients to a particular directory tree.  Synonym: CHROOT.",
+""
+};
+#endif /* CKROOT */
+
+static char *hmxxscrn[] = {
+"Syntax: SCREEN { CLEAR, CLEOL, MOVE row column }",
+#ifdef OS2
+"  Performs screen-formatting actions.",
+#else
+"  Performs screen-formatting actions.  Correct operation of these commands",
+"  depends on proper terminal setup on both ends of the connection -- mainly",
+"  that the host terminal type is set to agree with the kind of terminal or",
+"  the emulation you are viewing C-Kermit through.",
+#endif /* OS2 */
+" ",
+"SCREEN CLEAR",
+"  Moves the cursor to home position and clears the entire screen.",
+#ifdef OS2
+"  Synonyms: CLS, CLEAR SCREEN, CLEAR COMMAND-SCREEN ALL",
+#else
+"  Synonyms: CLS, CLEAR SCREEN.",
+#endif /* OS2 */
+" ",
+"SCREEN CLEOL",
+"  Clears from the current cursor position to the end of the line.",
+#ifdef OS2
+"  Synonym: CLEAR COMMAND-SCREEN EOL",
+#endif /* OS2 */
+" ",
+"SCREEN MOVE row column",
+"  Moves the cursor to the indicated row and column.  The row and column",
+"  numbers are 1-based so on a 24x80 screen, the home position is 1 1 and",
+"  the lower right corner is 24 80.  If a row or column number is given that",
+"  too large for what Kermit or the operating system thinks is your screen",
+"  size, the appropriate number is substituted.",
+" ",
+"Also see:",
+#ifdef OS2
+"  HELP FUNCTION SCRNCURX, HELP FUNCTION SCRNCURY, HELP FUNCTION SCRSTR,",
+#endif /* OS2 */
+"  SHOW VARIABLE TERMINAL, SHOW VARIABLE COLS, SHOW VAR ROWS, SHOW COMMAND.",
+""
+};
+
+#ifndef NOSPL
+static char *hmfword[] = {
+"\\fword(s1,n1,s2,s3,n2,n3) - Extract word from string.",
+"    s1 = source string",
+"    n1 = word number (1-based)",
+"    s2 = optional break set.",
+"    s3 = optional include set.",
+"    n2 = optional grouping mask.",
+"    n3 = optional separator flag:",
+"       0 = collapse adjacent separators",
+"       1 = don't collapse adjacent separators.",
+" ",
+"  Default break set is all characters except ASCII letters and digits.",
+"  ASCII (C0) control characters are always treated as break characters.",
+"  Default include set is null.",
+" ",
+"  If grouping mask given and nonzero, words can be grouped by quotes or",
+"  brackets selected by the sum of the following:",
+" ",
+"     1 = doublequotes:    \"a b c\"",
+"     2 = braces:          {a b c}",
+"     4 = apostrophes:     'a b c'",
+"     8 = parentheses:     (a b c)",
+"    16 = square brackets: [a b c]",
+"    32 = angle brackets:  <a b c>",
+" ",
+"  Nesting is possible with {}()[]<> but not with quotes or apostrophes.",
+" ",
+"Returns string:",
+"  Word number n, if there is one, otherwise an empty string.",
+""
+};
+
+static char *hmxxprompt[] = {
+"Syntax: PROMPT [ text ]",
+"  Enters interactive command level from within a script in such a way that",
+"  the script can be continued with an END or RETURN command.  STOP, EXIT,",
+"  SHOW STACK, TRACE, and Ctrl-C all have their normal effects.  The PROMPT",
+"  command allows variables to be examined or changed, or any other commands",
+"  to be given, in any number, prior to returning to the script, allowing",
+"  Kermit to serve as its own debugger; adding the PROMPT command to a script",
+"  is like setting a breakpoint.  If the optional text is included, it is",
+"  used as the new prompt for this level, e.g. \"prompt Breakpoint_1>\".",
+""
+};
+
+static char *hxxinp[] = {
+"Syntax:  INPUT [ /NOMATCH ] { number-of-seconds, time-of-day } [ text ]",
+"Example: INPUT 5 Login:  or  INPUT 23:59:59 RING",
+"  Waits up to the given number of seconds, or until the given time of day,",
+"  for the given text to arrive on the connection.  If no text is given,",
+"  INPUT waits for any character.  If the /NOMATCH switch is included, INPUT",
+"  does not attempt to match any characters, but continues reading from the",
+"  communication connection until the timeout interval expires.  If the",
+"  timeout interval is 0, the INPUT command does not wait; i.e. the given",
+"  text must already be available for reading for the INPUT command to",
+"  succeed.  If the interval is negative, the INPUT command waits forever.",
+"  For use in script programs with IF FAILURE and IF SUCCESS.  Also see",
+"  MINPUT, REINPUT, SET INPUT.  See HELP PAUSE for details on time-of-day",
+"  format.  The text, if given, can be a \\pattern() invocation, in which",
+"  case it is treated as a pattern rather than a literal string (HELP",
+"  PATTERNS for details).",
+""};
+
+static char *hxxout[] = {
+"Syntax: OUTPUT text",
+"  Sends the text out the communications connection, as if you had typed it",
+"  during CONNECT mode.  The text may contain backslash codes, variables,",
+"  etc, plus the following special codes:",
+" ",
+"    \\N - Send a NUL (ASCII 0) character (you can't use \\0 for this).",
+"    \\B - Send a BREAK signal.",
+"    \\L - Send a Long BREAK signal.",
+" ",
+"Also see SET OUTPUT.",
+"" };
+#endif /* NOSPL */
+
+static char *hxypari[] = {
+"SET PARITY NONE",
+"  Chooses 8 data bits and no parity.",
+" ",
+"SET PARITY { EVEN, ODD, MARK, SPACE }",
+"  Chooses 7 data bits plus the indicated kind of parity.",
+"  Forces 8th-bit prefixing during file transfer.",
+" ",
+#ifdef HWPARITY
+"SET PARITY HARDWARE { EVEN, ODD }",
+"  Chooses 8 data bits plus the indicated kind of parity.",
+" ",
+"Also see SET TERMINAL BYTESIZE, SET SERIAL, and SET STOP-BITS.",
+#else
+"Also see SET TERMINAL BYTESIZE and SET SERIAL.",
+#endif /* HWPARITY */
+""};
+
+#ifndef NOLOCAL
+static char *hxyesc[] = {
+#ifdef OS2
+"Syntax: SET ESCAPE number",
+"  Decimal ASCII value for escape character during CONNECT, normally 29",
+"  (Control-]).  Type the escape character followed by C to get back to the",
+"  C-Kermit prompt or followed by ? to see other options, or use the \\Kexit",
+"  keyboard verb, normally assigned to Alt-x.",
+#else
+#ifdef NEXT
+"Syntax: SET ESCAPE number",
+"  Decimal ASCII value for escape character during CONNECT, normally 29",
+"  (Control-]).  Type the escape character followed by C to get back to the",
+"  C-Kermit prompt or followed by ? to see other options.",
+#else
+"Syntax: SET ESCAPE number",
+"  Decimal ASCII value for escape character during CONNECT, normally 28",
+"  (Control-\\).  Type the escape character followed by C to get back to the",
+"  C-Kermit prompt or followed by ? to see other options.",
+#endif /* NEXT */
+#endif /* OS2 */
+" ",
+"You may also enter the escape character as ^X (circumflex followed by a",
+"letter or one of: @, ^, _, [, \\, or ], to indicate a control character;",
+"for example, SET ESC ^_ sets your escape character to Ctrl-Underscore.",
+" ",
+"You can also specify an 8-bit character (128-255) as your escape character,",
+"either by typing it literally or by entering its numeric code.",
+"" };
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+static char *hxyout[] = {
+"SET OUTPUT PACING <number>",
+"  How many milliseconds to pause after sending each OUTPUT character,",
+"  normally 0.",
+" ",
+"SET OUTPUT SPECIAL-ESCAPES { ON, OFF }",
+"  Whether to process the special OUTPUT-only escapes \\B, \\L, and \\N.",
+"  Normally ON (they are processed).",
+"" };
+
+static char *hxyinp[] = {
+"Syntax: SET INPUT parameter value",
+" ",
+#ifdef CK_AUTODL
+"SET INPUT AUTODOWNLOAD { ON, OFF }",
+"  Controls whether autodownloads are allowed during INPUT command execution.",
+" ",
+#endif /* CK_AUTODL */
+"SET INPUT BUFFER-LENGTH number-of-bytes",
+"  Removes the old INPUT buffer and creates a new one with the given length.",
+" ",
+"SET INPUT CANCELLATION { ON, OFF }",
+"  Whether an INPUT in progress can be can interrupted from the keyboard.",
+" ",
+"SET INPUT CASE { IGNORE, OBSERVE }",
+"  Tells whether alphabetic case is to be significant in string comparisons.",
+"  This setting is local to the current macro or command file, and is",
+"  inherited by subordinate macros and take files.",
+" ",
+"SET INPUT ECHO { ON, OFF }",
+"  Tells whether to display arriving characters read by INPUT on the screen.",
+" ",
+#ifdef CKFLOAT
+"SET INPUT SCALE-FACTOR <number>",
+"  A number to multiply all INPUT timeouts by, which may include a fractional",
+"  part, e.g. 2.5.  All INPUT commands that specify a timeout in seconds",
+"  (as opposed to a specific time of day) have their time limit adjusted",
+"  automatically by this factor, which is also available in the built-in",
+"  read-only variable \\v(inscale).  The default value is 1.0.",
+" ",
+
+#endif /* CKFLOAT */
+
+"SET INPUT SILENCE <number>",
+"  The maximum number to seconds of silence (no input at all) before the",
+"  INPUT command times out, 0 for no maximum.",
+" ",
+#ifdef OS2
+"SET INPUT TERMINAL { ON, OFF }",
+"  Determines whether the data received during an INPUT command is displayed",
+"  in the terminal window.  Default is ON.",
+" ",
+#endif /* OS2 */
+"SET INPUT TIMEOUT-ACTION { PROCEED, QUIT }",
+"  Tells whether to proceed or quit from a script program if an INPUT command",
+"  fails.  PROCEED (default) allows use of IF SUCCESS / IF FAILURE commands.",
+"  This setting is local to the current macro or command file, and is",
+"  inherited by subordinate macros and take files.",
+"" };
+
+static char *hxyfunc[] = {
+"SET FUNCTION DIAGNOSTICS { ON, OFF }",
+"  Whether to issue diagnostic messages for illegal function calls and",
+"  references to nonexistent built-in variables.  ON by default.",
+" ",
+"SET FUNCTION ERROR { ON, OFF }",
+"  Whether an illegal function call or reference to a nonexistent built-in",
+"  variable should cause a command to fail.  OFF by default.",
+"" };
+#endif /* NOSPL */
+
+static char *hxyxyz[] = {
+#ifdef CK_XYZ
+#ifdef XYZ_INTERNAL
+
+/* This is for built-in protocols */
+
+"Syntax: SET PROTOCOL { KERMIT, XMODEM, YMODEM, ZMODEM } [ s1 s2 [ s3 ] ]",
+"  Selects protocol to use for transferring files.  String s1 is a command to",
+"  send to the remote host prior to SENDing files with this protocol in",
+"  binary mode; string s2 is the same thing but for text mode.  Use \"%\" in",
+"  any of these strings to represent the filename(s).  If the protocol is",
+"  KERMIT, you may also specify a string s3, the command to start a Kermit",
+"  server on the remote host when you give a GET, REGET, REMOTE, or other",
+"  client command.  Use { braces } if any command contains spaces.  Examples:",
+" ",
+"    set proto xmodem {rx %s} {rx -a %s}",
+"    set proto kermit {kermit -YQir} {kermit -YQTr} {kermit -YQx}",
+
+#else /* This is for when non-Kermit protocols are external */
+
+"Syntax: \
+SET PROTOCOL { KERMIT, XMODEM, YMODEM, ZMODEM } [ s1 s2 s3 s4 s5 s6 ]",
+"  Selects protocol to use for transferring files.  s1 and s2 are commands to",
+"  output prior to SENDing with this protocol, to automatically start the",
+"  RECEIVE process on the other end in binary or text mode, respectively.",
+"  If the protocol is KERMIT, s3 is the command to start a Kermit server on",
+"  the remote computer, and there are no s4-s6 commands.  Otherwise, s3 and",
+"  s4 are commands used on this computer for sending files with this protocol",
+"  in binary or text mode, respectively; s5 and s6 are the commands for",
+"  receiving files with this protocol.  Use \"%s\" in any of these strings",
+"  to represent the filename(s).  Use { braces } if any command contains",
+"  spaces.  Examples:",
+" ",
+"    set proto kermit {kermit -YQir} {kermit -YQTr} {kermit -YQx}",
+"    set proto ymodem rb {rb -a} {sb %s} {sb -a %s} rb rb",
+" ",
+"External protocols require REDIRECT and external file transfer programs that",
+"use redirectable standard input/output.",
+#endif /* XYZ_INTERNAL */
+#else
+"Syntax: \
+SET PROTOCOL KERMIT [ s1 [ s2 [ s3 ] ] ]",
+"  Lets you specify the autoupload binary, autoupload text, and autoserver",
+"  command strings to be sent to the remote system in advance of any SEND",
+"  or GET commands.  By default these are \"kermit -ir\", \"kermit -r\", and",
+"  \"kermit -x\".  Use { braces } around any command that contains spaces.",
+"  Example:",
+" ",
+"    set proto kermit {kermit -Yir} {kermit -YTr} {kermit -Yx}",
+#endif /* CK_XYZ */
+" ",
+"  SHOW PROTOCOL displays the current settings.",
+""};
+
+static char *hmxxbye = "Syntax: BYE\n\
+  Shut down and log out a remote Kermit server";
+
+#ifdef CK_PERMS
+#ifdef UNIX
+static char *hmxxchmod[] = {
+"Syntax: CHMOD [ switches ] code filespec",
+"  UNIX only.  Changes permissions of the given file(s) to the given code,",
+"  which must be an octal number such as 664 or 775.  Optional switches:",
+" ",
+"   /FILES        Only change permissions of regular files.",
+"   /DIRECTORIES  Only change permissions of directory files.",
+"   /TYPE:BINARY  Only change permissions of binary files.",
+"   /TYPE:TEXT    Only change permissions of text files.",
+"   /DOTFILES     Include files whose names begin with dot (.).",
+"   /RECURSIVE    Change permissions in subdirectories too.",
+"   /LIST         List each file (synonym: /VERBOSE).",
+"   /NOLIST       Operate silently (synonym: /QUIET).",
+"   /PAGE         When listing, pause at end of each screen (implies /LIST).",
+"   /NOPAGE       When listing, don't pause at end of each screen.",
+"   /SIMULATE     Show what would be done but don't actually do it.",
+""
+};
+#endif /* UNIX */
+#endif /* CK_PERMS */
+
+#ifndef NOSPL
+#ifndef NOSEXP
+static char *hmxxsexp[] = {
+"Syntax: (operation operand [ operand [ ... ] ])",
+" ",
+"  C-Kermit includes a simple LISP-like S-Expression parser operating on",
+"  numbers only.  An S-Expression is always enclosed in parentheses.  The",
+"  parentheses can contain (a) a number, (b) a variable, (c) a function that",
+"  returns a number, or (d) an operator followed by one or more operands.",
+"  Operands can be any of (a) through (c) or an S-Expression.  Numbers can be",
+"  integers or floating-point.  Any operand that is not a number and does not",
+"  start with backslash (\\) is treated as a Kermit macro name.  Operators:",
+" ",
+" Operator  Action                                 Example           Value",
+"  EVAL (.)  Returns the contained value            (6)               6",
+"  QUOTE (') Inhibits evaluation of following value (quote a)         a",
+"  SETQ      Assigns a value to a global variable   (setq a 2)        2",
+"  LET       Assigns a value to a local variable    (let b -1.3)     -1.3",
+"  +         Adds all operands (1 or more)          (+ a b)           0.7",
+"  -         Subtracts all operands (1 or more)     (- 9 5 2 1)       1",
+"  *         Multiplies all operands (1 or more)    (* a (+ b 1) 3)  -1.8",
+"  /         Divides all operands (1 or more)       (/ b a 2)        -0.325",
+"  ^         Raise given number to given power      (^ 3 2)           9",
+"  ++        Increments a variable                  (++ a 1.2)        3.2",
+"  --        Decrements a variable                  (-- a)            1",
+"  ABS       Absolute value of 1 operand            (abs (* a b 3))   7.8",
+"  MAX       Maximum of all operands (1 or more)    (max 1 2 3 4)     4",
+"  MIN       Minimum of all operands (1 or more)    (min 1 2 3 4)     1",
+"  MOD       Modulus of all operands (1 or more)    (mod 7 4 2)       1",
+"  TRUNCATE  Integer part of floating-point operand (truncate 1.333)  1",
+"  CEILING   Ceiling of floating-point operand      (ceiling 1.25)    2",
+"  FLOOR     Floor of floating-point operand        (floor 1.25)      1",
+"  ROUND     Operand rounded to nearest integer     (round 1.75)      2",
+"  SQRT      Square root of 1 operand               (sqrt 2)          1.414..",
+"  EXP       e (2.71828..) to the given power       (exp -1)          0.367..",
+"  SIN       Sine of angle expressed in radians     (sin (/ pi 2))    1.0",
+"  COS       Cosine of given number                 (cos pi)         -1.0",
+"  TAN       Tangent of given number                (tan pi)          0.0",
+"  LOG       Natural log (base e) of given number   (log 2.7183)      1.000..",
+"  LOG10     Log base 10 of given number            (log10 1000)      3.0",
+" ",
+"Predicate operators return 0 if false, 1 if true, and if it is the outermost",
+"operator, sets SUCCESS or FAILURE accordingly:",
+" ",
+"  <         Operands in strictly descending order  (< 6 5 4 3 2 1)   1",
+"  <=        Operands in descending order           (<= 6 6 5 4 3 2)  1",
+"  !=        Operands are not equal                 (!= 1 1 1.0)      0",
+"  =   (==)  All operands are equal                 (= 3 3 3 3)       1",
+"  >         Operands in strictly ascending order   (> 1 2 3 4 5 6)   1",
+"  >=        Operands in ascending order            (> 1 1 2 3 4 5)   1",
+"  AND (&&)  Operands are all true                  (and 1 1 1 1 0)   0",
+"  OR  (||)  At least one operand is true           (or 1 1 1 1 0)    1",
+"  XOR       Logical Exclusive OR                   (xor 3 1)         0",
+"  NOT (!)   Reverses truth value of operand        (not 3)           0",
+" ",
+"Bit-oriented operators:",
+" ",
+"  &         Bitwise AND                            (& 7 2)           2",
+"  |         Bitwise OR                             (| 1 2 3 4)       7",
+"  #         Bitwise Exclusive OR                   (# 3 1)           2",
+"  ~         Reverses all bits                      (~ 3)            -4",
+" ",
+"Operators that work on truth values:",
+" ",
+"  IF        Conditional evaluation                 (if (1) 2 3)      2",
+" ",
+"Operators can also be names of Kermit macros that return either numeric",
+"values or no value at all.",
+" ",
+"Built-in constants are:",
+" ",
+"  t         True (1)",
+"  nil       False (empty)",
+"  pi        The value of Pi (3.1415926...)",
+" ",
+"If SET SEXPRESSION ECHO-RESULT is AUTO (the default), the value of the",
+"S-Expression is printed if the S-Expression is given at top level; if ON,",
+"it is printed at any level; if OFF it is not printed.  At all levels, the",
+"variable \\v(sexpression) is set to the most recent S-Expression, and",
+"\\v(svalue) is set to its value.  You can use the \\fsexpresssion() function",
+"to evaluate an S-Expression anywhere in a Kermit command.",
+""
+};
+#endif /* NOSEXP */
+#endif /* NOSPL */
+
+static char *hmxxgrep[] = {
+#ifdef UNIXOROSK
+"Syntax: GREP [ options ] pattern filespec",
+#else
+"Syntax: FIND [ options ] pattern filespec",
+#endif /* UNIXOROSK */
+"  Searches through the given file or files for the given character string",
+"  or pattern.  In the normal case, all lines containing any text that matches"
+,
+"  the pattern are printed.  Pattern syntax is as described in HELP PATTERNS",
+"  except that '*' is implied at the beginning unless the pattern starts with",
+"  '^' and also at the end unless the pattern ends with '$'.  Therefore,",
+"  \"grep something *.txt\" lists all lines in all *.txt files that contain",
+"  the word \"something\", but \"grep ^something *.txt\" lists only the lines",
+"  that START with \"something\".  The command succeeds if any of the given",
+"  files contained any lines that match the pattern, otherwise it fails.",
+#ifdef UNIXOROSK
+"  Synonym: FIND.",
+#else
+"  Synonym: GREP.",
+#endif /* UNIXOROSK */
+" ",
+"File selection options:",
+"  /NOBACKUPFILES",
+"    Excludes backup files (like oofa.txt.~3~) from the search.",
+"  /DOTFILES",
+"    Includes files whose names start with dot (.) in the search.",
+"  /NODOTFILES",
+"    Excludes files whose names start with dot (.) from the search.",
+#ifdef RECURSIVE
+"  /RECURSIVE",
+"    Searches through files in subdirectories too.",
+#endif /* RECURSIVE */
+"  /TYPE:TEXT",
+"    Search only text files (requires FILE SCAN ON).",
+"  /TYPE:BINARY",
+"    Search only binary files (requires FILE SCAN ON).",
+" ",
+"Pattern-matching options:",
+"  /NOCASE",
+"    Ignores case of letters (ASCII only) when comparing.",
+"  /NOMATCH",
+"    Searches for lines that do NOT match the pattern.",
+" ",
+"Display options:",
+"  /COUNT:variable-name",
+"    For each file, prints only the filename and a count of matching lines",
+"    and assigns the total match count to the variable, if one is given.",
+"  /NAMEONLY",
+"    Prints the name of each file that contains at least one matching line,",
+"    one name per line, rather than showing each matching line.",
+"  /NOLIST",
+"    Doesn't print anything (but sets SUCCESS or FAILURE appropriately).",
+"  /LINENUMBERS",
+"    Precedes each file line by its line number within the file.",
+"  /PAGE",
+"    Pauses after each screenful.",
+"  /NOPAGE",
+"    Doesn't pause after each screenful.",
+"  /OUTPUT:name",
+"    Sends results to the given file.  If this switch is omitted, the",
+"    results appear on your screen.  This switch overrides any express or",
+"    implied /PAGE switch.",
+""};
+
+static char *hmxxdir[] = {
+#ifdef DOMYDIR
+"Syntax: DIRECTORY [ switches ] [ filespec [ filespec [ ... ] ] ]",
+#ifdef LOCUS
+"  If LOCUS is REMOTE or LOCUS is AUTO and you have an FTP connection,",
+"  this command is equivalent to REMOTE DIRECTORY (RDIR).  Otherwise:",
+" ",
+#endif /* LOCUS */
+"  Lists local files.  The filespec may be a filename, possibly containing",
+"  wildcard characters, or a directory name.  If no filespec is given, all",
+"  files in the current directory are listed.  If a directory name is given,",
+"  all the  files in it are listed.  Multiple filespecs can be given.",
+"  Optional switches:",
+" ",
+"   /BRIEF           List filenames only.",
+#ifdef CK_PERMS
+"   /VERBOSE       + Also list permissions, size, and date.",
+#else
+"   /VERBOSE       + Also list date and size.",
+#endif /* CK_PERMS */
+"   /FILES           Show files but not directories.",
+"   /DIRECTORIES     Show directories but not files.",
+"   /ALL           + Show both files and directories.",
+"   /ARRAY:&a        Store file list in specified array (e.g. \\%a[]).",
+"   /PAGE            Pause after each screenful.",
+"   /NOPAGE          Don't pause after each screenful.",
+#ifdef UNIXOROSK
+"   /DOTFILES        Include files whose names start with dot (period).",
+"   /NODOTFILES    + Don't include files whose names start with dot.",
+"   /FOLLOWLINKS     Follow symbolic links.",
+"   /NOFOLLOWLINKS + Don't follow symbolic links.",
+"   /BACKUP        + Include backup files (names end with .~n~).",
+"   /NOBACKUPFILES   Don't include backup files.",
+#endif /* UNIXOROSK */
+"   /OUTPUT:file     Store directory listing in the given file.",
+"   /HEADING         Include heading and summary.",
+"   /NOHEADING     + Don't include heading or summary.",
+"   /SUMMARY         Print only count and total size of matching files.",
+"   /XFERMODE        Show pattern-based transfer mode (T=Text, B=Binary).",
+"   /TYPE:           Show only files of the specified type (text or binary).",
+"   /MESSAGE:text    Add brief message to each listing line.",
+"   /NOMESSAGE     + Don't add message to each listing line.",
+"   /NOXFERMODE    + Don't show pattern-based transfer mode",
+"   /ISODATE       + In verbose listings, show date in ISO 8061 format.",
+"   /ENGLISHDATE     In verbose listings, show date in \"English\" format.",
+#ifdef RECURSIVE
+"   /RECURSIVE       Descend through subdirectories.",
+"   /NORECURSIVE   + Don't descend through subdirectories.",
+#endif /* RECURSIVE */
+"   /SORT:key        Sort by key, NAME, DATE, or SIZE; default key is NAME.",
+"   /NOSORT        + Don't sort.",
+"   /ASCENDING     + If sorting, sort in ascending order.",
+"   /REVERSE         If sorting, sort in reverse order.",
+" ",
+"Factory defaults are marked with +.  Default for paging depends on SET",
+"COMMAND MORE-PROMPTING.  Use SET OPTIONS DIRECTORY [ switches ] to change",
+"defaults; use SHOW OPTIONS to display customized defaults.",
+#else
+"Syntax: DIRECTORY [ filespec ]",
+"  Lists the specified file or files.  If no filespec is given, all files",
+"  in the current directory are listed.",
+#endif /* DOMYDIR */
+""};
+
+
+#ifndef NOSPL
+static char *hmxxkcd[] = {
+"Syntax: KCD symbolic-directory-name",
+"  Kermit Change Directory: Like CD (q.v.) but (a) always acts locally, and",
+"  (b) takes a symbolic directory name rather than an actual directory name.",
+"  The symbolic names correspond to Kermit's directory-valued built-in",
+"  variables, such as \\v(download), \\v(exedir), and so on.  Here's the list:"
+,
+" ",
+#ifdef NT
+"    appdata       Your personal Kermit 95 application data directory",
+"    common        Kermit 95's application data directory for all users",
+"    desktop       Your Windows desktop",
+#endif /* NT */
+"    download      Your download directory (if any)",
+#ifdef OS2ORUNIX
+"    exedir        The directory where the Kermit executable resides",
+#endif /* OS2ORUNIX */
+"    home          Your home, login, or default directory",
+"    inidir        The directory where Kermit's initialization was found",
+#ifdef UNIX
+"    lockdir       The UNIX UUCP lockfile directory on this computer",
+#endif /* UNIX */
+#ifdef NT
+"    personal      Your \"My Documents\" directory",
+#endif /* NT */
+"    startup       Your current directory at the time Kermit started",
+"    textdir       The directory where Kermit text files reside, if any",
+"    tmpdir        Your temporary directory",
+" ",
+"  Also see CD, SET FILE DOWNLOAD, SET TEMP-DIRECTORY.",
+""
+};
+#endif /* NOSPL */
+
+static char *hmxxcwd[] = {
+#ifdef LOCUS
+"  If LOCUS is REMOTE or LOCUS is AUTO and you have an FTP connection,",
+"  this command is equivalent to REMOTE CD (RCD).  Otherwise:",
+" ",
+#endif /* LOCUS */
+#ifdef vms
+"Syntax: CD [ directory or device:directory ]",
+"  Change Working Directory.  Equivalent to VMS SET DEFAULT command.",
+#else
+#ifdef datageneral
+"Change Working Directory, equivalent to AOS/VS 'dir' command.",
+#else
+#ifdef OS2
+"Syntax: CD [ disk or directory name ]",
+"  Change Disk or Directory.  If a disk or directory name is not specified,",
+"  your current directory becomes the one specified by HOME environment",
+"  variable, if any.  A disk letter must be followed by a colon.",
+#else
+"Syntax: CD [ directory name ]",
+"  Change Directory.  Changes your current, working, default directory to the",
+"  one given, so that future non-absolute filename references are relative to",
+"  this directory.  If the directory name is omitted, your home (login)",
+"  directory is supplied.",
+#endif /* OS2 */
+#endif /* datageneral */
+#endif /* vms */
+"  C-Kermit's default prompt shows your current directory.",
+"  Synonyms: LCD, CWD.",
+#ifdef LOCUS
+"  Also see: SET LOCUS, PWD, CDUP, BACK, REMOTE CD (RCD), SET CD, SET PROMPT.",
+#else
+"  Also see: PWD, CDUP, BACK, REMOTE CD (RCD), SET CD, SET PROMPT.",
+#endif /* LOCUS */
+#ifndef NOSPL
+"  And see: HELP KCD.",
+#endif /* NOSPL */
+"  Relevant environment variables: CDPATH, HOME.",
+""};
+
+static char *hmxxdel[] = {
+"Syntax: DELETE [ switches... ] filespec",
+#ifdef LOCUS
+"  If LOCUS is REMOTE or LOCUS is AUTO and you have an FTP connection,",
+"  this command is equivalent to REMOTE DELETE (RDELETE).  Otherwise:",
+" ",
+#endif /* LOCUS */
+"  Deletes a file or files on the computer where C-Kermit is running.",
+"  The filespec may denote a single file or can include wildcard characters",
+"  to match multiple files.  RM is a synonym for DELETE.  Switches include:",
+" ",
+"/AFTER:date-time",
+#ifdef VMS
+"  Specifies that only those files created after the given date-time are",
+#else
+"  Specifies that only those files modified after the given date-time are",
+#endif /* VMS */
+"  to be deleted.  HELP DATE for info about date-time formats.",
+" ",
+"/BEFORE:date-time",
+#ifdef VMS
+"  Specifies that only those files modified before the given date-time",
+#else
+"  Specifies that only those files modified before the given date-time",
+#endif /* VMS */
+"  are to be deleted.",
+" ",
+"/NOT-AFTER:date-time",
+#ifdef VMS
+"  Specifies that only those files modified at or before the given date-time",
+#else
+"  Specifies that only those files modified at or before the given date-time",
+#endif /* VMS */
+"  are to be deleted.",
+" ",
+"/NOT-BEFORE:date-time",
+#ifdef VMS
+"  Specifies that only those files modified at or after the given date-time",
+#else
+"  Specifies that only those files modified at or after the given date-time",
+#endif /* VMS */
+"  are to be deleted.",
+" ",
+"/LARGER-THAN:number",
+"  Specifies that only those files longer than the given number of bytes are",
+"  to be deleted.",
+" ",
+"/SMALLER-THAN:number",
+"  Specifies that only those files smaller than the given number of bytes are",
+"  to be sent.",
+" ",
+"/EXCEPT:pattern",
+"  Specifies that any files whose names match the pattern, which can be a",
+"  regular filename or may contain wildcards, are not to be deleted.  To",
+"  specify multiple patterns (up to 8), use outer braces around the group",
+"  and inner braces around each pattern:",
+" ",
+"    /EXCEPT:{{pattern1}{pattern2}...}",
+" ",
+#ifdef UNIXOROSK
+"/DOTFILES",
+"  Include (delete) files whose names begin with \".\".",
+" ",
+"/NODOTFILES",
+"  Skip (don't delete) files whose names begin with \".\".",
+" ",
+#endif /* UNIXOROSK */
+"/TYPE:TEXT",
+"  Delete only regular text files (requires FILE SCAN ON)",
+" ",
+"/TYPE:BINARY",
+"  Delete only regular binary files (requires FILE SCAN ON)",
+" ",
+"/DIRECTORIES",
+"  Include directories.  If this switch is not given, only regular files",
+"  are deleted.  If it is given, Kermit attempts to delete any directories",
+"  that match the given file specification, which succeeds only if the",
+"  directory is empty.",
+" ",
+#ifdef RECURSIVE
+"/RECURSIVE",
+"  The DELETE command applies to the entire directory tree rooted in the",
+"  current or specified directory.  When the /DIRECTORIES switch is also",
+"  given, Kermit deletes all the (matching) files in each directory before",
+"  attempting to delete the directory itself.",
+" ",
+#endif /* RECURSIVE */
+#ifdef UNIX
+#ifdef RECURSIVE
+"/ALL",
+"  This is a shortcut for /RECURSIVE /DIRECTORIES /DOTFILES.",
+#else
+"/ALL",
+"  This is a shortcut for /DIRECTORIES /DOTFILES.",
+#endif /* RECURSIVE */
+#else  /* !UNIX */
+#ifdef RECURSIVE
+"/ALL",
+"  This is a shortcut for /RECURSIVE /DIRECTORIES.",
+#else
+"/ALL",
+"  This is a synonym for /DIRECTORIES.",
+#endif /* RECURSIVE */
+#endif /* UNIX */
+" ",
+"/LIST",
+"  List each file and tell whether it was deleted.  Synonyms: /LOG, /VERBOSE.",
+" ",
+"/NOLIST",
+"  Don't list files while deleting.  Synonyms: /NOLOG, /QUIET.",
+" ",
+"/HEADING",
+"  Print heading and summary information.",
+" ",
+"/NOHEADING",
+"  Don't print heading and summary information.",
+" ",
+"/SUMMARY",
+"  Like /HEADING /NOLIST, but only prints the summary line.",
+" ",
+"/PAGE",
+"  If listing, pause after each screenful.",
+" ",
+"/NOPAGE",
+"  Don't pause after each screenful.",
+" ",
+"/ASK",
+"  Interactively ask permission to delete each file.  Reply Yes or OK to",
+"  delete it, No not to delete it, Quit to cancel the DELETE command, and",
+"  Go to go ahead and delete all the rest of the files without asking.",
+" ",
+"/NOASK",
+"  Delete files without asking permission.",
+" ",
+"/SIMULATE",
+"  Preview files selected for deletion without actually deleting them.",
+"  Implies /LIST.",
+" ",
+"Use SET OPTIONS DELETE to make selected switches effective for every DELETE",
+"command \
+unless you override them; use SHOW OPTIONS to see selections currently",
+#ifdef LOCUS
+"in effect.  Also see HELP SET LOCUS, HELP PURGE, HELP WILDCARD.",
+#else
+"in effect.  Also see HELP PURGE, HELP WILDCARD.",
+#endif /* LOCUS */
+""};
+
+#ifndef NOHTTP
+static char *hmxxhttp[] = {
+"Syntax:",
+#ifdef CK_SSL
+"HTTP [ <switches> ] OPEN [{ /SSL, /TLS }] <hostname> <service/port>",
+#else
+"HTTP [ <switches> ] OPEN <hostname> <service/port>",
+#endif /*CK_SSL */
+"  Instructs Kermit to open a new connection for HTTP communication with",
+"  the specified host on the specified port.  The default port is \"http\".",
+#ifdef CK_SSL
+"  If /SSL or /TLS are specified or if the service is \"https\" or port 443,",
+"  a secure connection will be established using the current authentication",
+"  settings.  See HELP SET AUTH for details.",
+#endif /* CK_SSL */
+"  If <switches> are specified, they are applied to all subsequent HTTP",
+"  actions (GET, PUT, ...) until an HTTP CLOSE command is executed.",
+"  A URL can be included in place of the hostname and service or port.",
+" ",
+"HTTP CLOSE",
+"  Instructs Kermit to close any open HTTP connection and clear any saved",
+"  switch values.",
+" ",
+"HTTP [ <switches> ] CONNECT <host>[:<port>]",
+"  Instructs the server to establish a connection with the specified host",
+"  and to redirect all data transmitted between Kermit and the host for the",
+"  life of the connection.",
+" ",
+"HTTP [ <switches> ] GET <remote-filename> [ <local-filename> ]",
+"  Retrieves the named file on the currently open HTTP connection.  The",
+"  default local filename is the same as the remote filename, but with any",
+"  path stripped.  If you want the file to be displayed on the screen instead",
+"  of stored on disk, include the /TOSCREEN switch and omit the local",
+"  filename.  If you give a URL instead of a remote filename, this commands",
+"  opens the connection, GETs the file, and closes the connection; the same",
+"  is true for the remaining HTTP commands for which you can specify a",
+"  remote filename, directory name, or path.",
+" ",
+"HTTP [ <switches> ] HEAD <remote-filename> [ <local-filename> ]",
+"  Like GET except without actually getting the file; instead it gets only",
+"  the headers, storing them into the given file (if a local filename is",
+"  specified), one line per header item as shown in the /ARRAY: switch",
+"  description.",
+" ",
+"HTTP [ <switches> ] INDEX <remote-directory> [ <local-filename> ]",
+"  Retrieves the file listing for the given server directory.",
+"  NOTE: This command is not supported by most Web servers, and even when",
+"  the server understand it, there is no stardard response format.",
+" ",
+"HTTP [ <switches> ] POST [ /MIME-TYPE:<type> ] <local-file> <remote-path>",
+"     [ <dest-file> ]",
+"  Used to send a response as if it were sent from a form.  The data to be",
+"  posted must be read from a file.",
+" ",
+"HTTP [ <switches> ] PUT [ /MIME-TYPE:<type> ] <local-file> <remote-file>",
+"     [ <dest-file> ]",
+"  Uploads the given local file to server file.  If the remote filename is",
+"  omitted, the local name is used, but with any path stripped.",
+" ",
+"HTTP [ <switches> ] DELETE <remote-filename>",
+"  Instructs the server to delete the specified filename.",
+" ",
+"where <switches> are:",
+"/AGENT:<user-agent>",
+"  Identifies the client to the server; \"C-Kermit\" or \"Kermit-95\"",
+"  by default.",
+" ",
+"/HEADER:<header-line>",
+"  Used for specifying any optional headers.  A list of headers is provided",
+"  using braces for grouping:",
+" ",
+"    /HEADER:{{<tag>:<value>}{<tag>:<value>}...}",
+" ",
+"  For a listing of valid <tag> value and <value> formats see RFC 1945:",
+"  \"Hypertext Transfer Protocol -- HTTP/1.0\".  A maximum of eight headers",
+"  may be specified.",
+" ",
+"/TOSCREEN",
+"  Display server responses on the screen.",
+" ",
+"/USER:<name>",
+"  In case a page requires a username for access.",
+" ",
+"/PASSWORD:<password>",
+"  In case a page requires a password for access.",
+" ",
+"/ARRAY:<arrayname>",
+"  Tells Kermit to store the response headers in the given array, one line",
+"  per element.  The array need not be declared in advance.  Example:",
+" ",
+"    http /array:c get kermit/index.html",
+"    show array c",
+"    Dimension = 9",
+"    1. Date: Fri, 26 Nov 1999 23:12:22 GMT",
+"    2. Server: Apache/1.3.4 (Unix)",
+"    3. Last-Modified: Mon, 06 Sep 1999 22:35:58 GMT",
+"    4. ETag: \"bc049-f72-37d441ce\"",
+"    5. Accept-Ranges: bytes",
+"    6. Content-Length: 3954",
+"    7. Connection: close     ",
+"    8. Content-Type: text/html",
+" ",
+"As you can see, the header lines are like MIME e-mail header lines:",
+"identifier, colon, value.  The /ARRAY switch is the only method available",
+"to a script to process the server responses for a POST or PUT command.",
+" ",
+""
+};
+#endif /* NOHTTP */
+
+#ifdef CK_KERBEROS
+static char *hmxxauth[] = {
+"Syntax:",
+"AUTHENTICATE { KERBEROS4, KERBEROS5 [ switches ] } <action> [ switches ]",
+"  Obtains or destroys Kerberos tickets and lists information about them.",
+"  Actions are INITIALIZE, DESTROY, and LIST-CREDENTIALS.  KERBEROS4 can be",
+"  abbreviated K4 or KRB4; KERBEROS5 can be abbreviated K5 or KRB5.  Use ? to",
+"  see which keywords, switches, or other quantities are valid at each point",
+"  in the command.",
+" ",
+"  The actions are INITIALIZE, DESTROY, and LIST-CREDENTIALS:",
+" ",
+"    AUTH { K4, K5 } { INITIALIZE [switches], DESTROY,",
+"      LIST-CREDENTIALS [switches] }",
+" ",
+"  The INITIALIZE action is the most complex, and its format is different",
+"  for Kerberos 4 and Kerberos 5.  The format for Kerberos 4 is:",
+" ",
+"  AUTH K4 INITIALIZE [ /INSTANCE:<name> /LIFETIME:<minutes> -",
+"    /PASSWORD:<password> /PREAUTH /REALM:<name> <principal> ]",
+" ",
+"  All switches are optional.  Kerberos 4 INITIALIZE switches are:",
+" ",
+"  /INSTANCE:<name>",
+"    Allows an Instance (such as a hostname) to be specified.",
+" ",
+"  /LIFETIME:<number>",
+"    Specifies the requested lifetime in minutes for the ticket.  If no",
+"    lifetime is specified, 600 minutes is used.  If the lifetime is greater",
+"    than the maximum supported by the ticket granting service, the resulting",
+"    lifetime is shortened accordingly.",
+" ",
+"  /NOT-PREAUTH",
+"    Instructs Kermit to send a ticket getting ticket (TGT) request to the",
+"    KDC without any preauthentication data.",
+" ",
+"  /PASSWORD:<string>",
+"    Allows a password to be included on the command line or in a script",
+"    file.  If no /PASSWORD switch is included, you are prompted on a separate"
+,
+"    line.  The password switch is provided on a use-at-your-own-risk basis",
+"    for use in automated scripts.  WARNING: Passwords should not be stored in"
+,
+"    files.",
+" ",
+"  /PREAUTH",
+"    Instructs Kermit to send a preauthenticated Ticket-Getting Ticket (TGT)",
+"    request to the KDC instead of a plaintext request.  The default when",
+"    supported by the Kerberos libraries.",
+" ",
+"  /REALM:<name>",
+"    Allows a realm to be specified (overriding the default realm).",
+" ",
+"  <principal>",
+"    Your identity in the given or default Kerberos realm, of the form:",
+"    userid[.instance[.instance]]@[realm]  ",
+"    Can be omitted if it is the same as your username or SET LOGIN USERID",
+"    value on the client system.",
+" ",
+"  The format for Kerberos 5 is as follows:",
+" ",
+"  AUTH K5 [ /CACHE:<filename> ] { INITIALIZE [ switches ], DESTROY,",
+"    LIST-CREDENTIALS ...}",
+" ",
+"The INITIALIZE command for Kerberos 5 can include a number of switches;",
+"all are optional:",
+" ",
+"AUTH K5 [ /CACHE:<filename> ] INITITIALIZE [ /ADDRESSES:<addr-list>",
+"  /FORWARDABLE /KERBEROS4 /LIFETIME:<minutes> /PASSWORD:<password>",
+"  /POSTDATE:<date-time> /PROXIABLE /REALM:<name> /RENEW /RENEWABLE:<minutes>",
+"  /SERVICE:<name> /VALIDATE <principal> ]",
+" ",
+"  All Kerberos 5 INITIALIZE switches are optional:",
+" ",
+"  /ADDRESSES:{list of ip-addresses}",
+"    Specifies a list of IP addresses that should be placed in the Ticket",
+"    Getting Ticket in addition to the local machine addresses.",
+" ",
+"  /FORWARDABLE",
+"    Requests forwardable tickets.",
+" ",
+"  /INSTANCE:<name>",
+"    Allows an Instance (such as a hostname) to be specified.",
+" ",
+"  /KERBEROS4",
+"    Instructs Kermit to get Kerberos 4 tickets in addition to Kerberos 5",
+"    tickets.  If Kerberos 5 tickets are not supported by the server, a",
+"    mild warning is printed and Kerberos 4 tickets are requested.",
+" ",
+"  /LIFETIME:<number>",
+"    Specifies the requested lifetime in minutes for the ticket.  If no",
+"    lifetime is specified, 600 minutes is used.  If the lifetime is greater",
+"    than the maximum supported by the ticket granting service, the resulting",
+"    lifetime is shortened.",
+" ",
+"  /NO-KERBEROS4",
+"    Instructs Kermit to not attempt to retrieve Kerberos 4 credentials.",
+" ",
+"  /NOT-FORWARDABLE",
+"    Requests non-forwardable tickets.",
+" ",
+"  /NOT-PROXIABLE",
+"    Requests non-proxiable tickets.",
+" ",
+"  /PASSWORD:<string>",
+"    Allows a password to be included on the command line or in a script",
+"    file.  If no /PASSWORD switch is included, you are prompted on a separate"
+,
+"    line.  The password switch is provided on a use-at-your-own-risk basis",
+"    for use in automated scripts.  WARNING: Passwords should not be stored in"
+,
+"    files.",
+" ",
+"  /POSTDATE:<date-time>",
+"    Requests a postdated ticket, valid starting at <date-time>.  Postdated",
+"    tickets are issued with the invalid flag set, and need to be fed back to",
+"    the KDC before use with the /VALIDATE switch.  Type HELP DATE for info",
+"    on date-time formats.",
+" ",
+"  /PROXIABLE",
+"    Requests proxiable tickets.",
+" ",
+"  /REALM:<string>",
+"    Allows an alternative realm to be specified.",
+" ",
+"  /RENEW",
+"    Requests renewal of a renewable Ticket-Granting Ticket.  Note that ",
+"    an expired ticket cannot be renewed even if it is within its renewable ",
+"    lifetime.",
+" ",
+"  /RENEWABLE:<number>",
+"    Requests renewable tickets, with a total lifetime of <number> minutes.",
+" ",
+"  /SERVICE:<string>",
+"    Allows a service other than the ticket granting service to be specified.",
+" ",
+"  /VALIDATE",
+"    Requests that the Ticket Granting Ticket in the cache (with the invalid",
+"    flag set) be passed to the KDC for validation.  If the ticket is within",
+"    its requested time range, the cache is replaced with the validated",
+"    ticket.",
+" ",
+"  <principal>",
+"    Your identity in the given or default Kerberos realm, of the form:",
+"    userid[/instance][@realm]  ",
+"    Can be omitted if it is the same as your username or SET LOGIN USERID",
+"    value on the client system.",
+" ",
+"  Note: Kerberos 5 always attempts to retrieve a Ticket-Getting Ticket (TGT)",
+"  using the preauthenticated TGT request.",
+" ",
+"  AUTHORIZE K5 LIST-CREDENTIALS [ /ADDRESSES /FLAGS /ENCRYPTION ]",
+" ",
+"  Shows start time, expiration time, service or principal name, plus",
+"  the following additional information depending the switches:",
+" ",
+"  /ADDRESSES displays the hostnames and/or IP addresses embedded within",
+"    the tickets.",
+" ",
+"  /FLAGS provides the following information (if applicable) for each ticket:",
+"    F - Ticket is Forwardable",
+"    f - Ticket was Forwarded",
+"    P - Ticket is Proxiable",
+"    p - Ticket is a Proxy",
+"    D - Ticket may be Postdated",
+"    d - Ticket has been Postdated",
+"    i - Ticket is Invalid",
+"    R - Ticket is Renewable",
+"    I - Ticket is the Initial Ticket",
+"    H - Ticket has been authenticated by Hardware",
+"    A - Ticket has been Pre-authenticated",
+" ",
+"  /ENCRYPTION displays the encryption used by each ticket (if applicable):",
+"    DES-CBC-CRC",
+"    DES-CBC-MD4",
+"    DES-CBC-MD5",
+"    DES3-CBC-SHA",
+""
+};
+#endif /* CK_KERBEROS */
+
+#ifndef NOCSETS
+static char *hmxxassoc[] = {
+"ASSOCIATE FILE-CHARACTER-SET <file-character-set> <transfer-character-set>",
+"  Tells C-Kermit that whenever the given file-character set is selected, and",
+"  SEND CHARACTER-SET (q.v.) is AUTOMATIC, the given transfer character-set",
+"  is selected automatically.",
+" ",
+"ASSOCIATE XFER-CHARACTER-SET <xfer-character-set> <file-character-set>",
+"  Tells C-Kermit that whenever the given transfer-character set is selected,",
+"  either by command or by an announcer attached to an incoming text file,",
+"  and SEND CHARACTER-SET is AUTOMATIC, the specified file character-set is",
+"  to be selected automatically.  Synonym: ASSOCIATE TRANSFER-CHARACTER-SET.",
+" ",
+"Use SHOW ASSOCIATIONS to list the current character-set associations, and",
+"SHOW CHARACTER-SETS to list the current settings.",
+""
+};
+#endif /* NOCSETS */
+
+static char *hmxxpat[] = {
+"A \"pattern\" is notation used in a search string when searching through",
+"text.  C-Kermit uses three kinds of patterns: floating patterns, anchored",
+"patterns, and wildcards.  Wildcards are anchored patterns that are used to",
+"match file names; type HELP WILDCARD to learn about them.",
+" ",
+"In a pattern, certain characters are special:",
+" ",
+"* Matches any sequence of zero or more characters.  For example, \"k*t\"",
+"  matches all strings that start with \"k\" and end with \"t\" including",
+"  \"kt\", \"kit\", \"knight\", or \"kermit\".",
+" ",
+#ifdef VMS
+"% Matches any single character.  For example, \"k%%%%t\" matches all strings",
+#else
+"? Matches any single character.  For example, \"k????t\" matches all strings",
+#endif /* VMS */
+"  that are exactly 6 characters long and start with \"k\" and end with",
+#ifdef VMS
+"  with \"t\".",
+#else
+"  with \"t\".  When typing commands at the prompt, you must precede any",
+"  question mark to be used for matching by a backslash (\\) to override the",
+"  normal function of question mark, which is providing menus and file lists.",
+#endif /* VMS */
+" ",
+#ifdef OS2ORUNIX
+#ifdef CKREGEX
+"[abc]",
+"  Square brackets enclosing a list of characters matches any character in",
+"  the list.  Example: h[aou]t matches hat, hot, and hut.",
+" ",
+"[a-z]",
+"  Square brackets enclosing a range of characters matches any character in",
+"  the range; a hyphen (-) separates the low and high elements of the range.",
+"  For example, [a-z] matches any character from a to z.",
+" ",
+"[acdm-z]",
+"  Lists and ranges may be combined.  This example matches a, c, d, or any",
+"  letter from m through z.",
+" ",
+"{string1,string2,...}",
+"  Braces enclose a list of strings to be matched.  For example:",
+"  ker{mit,nel,beros} matches kermit, kernel, and kerberos.  The strings",
+"  may themselves contain *, ?, [abc], [a-z], or other lists of strings.",
+#endif /* CKREGEX */
+#endif /* OS2ORUNIX */
+#ifndef NOSPL
+" ",
+"To force a special pattern character to be taken literally, precede it with",
+"a backslash, e.g. [a\\-z] matches a, hyphen, and z rather than a through z.",
+" ",
+"A floating  pattern can also include the following special characters:",
+" ",
+"^ (First character of pattern) Anchors the pattern at the beginning.",
+"$ (Last character of pattern) Anchors the pattern at the end.",
+" ",
+"If a floating pattern does not start with \"^\", the pattern can match",
+"anywhere in the string instead of only at the beginning; in other words, a",
+"leading \"*\" is assumed.  Similarly, if the pattern doesn't end with \"$\",",
+"a trailing \"*\" is assumed.",
+" ",
+"The following commands and functions use floating patterns:",
+"  GREP [ <switches> ] <pattern> <filespec>",
+"  TYPE /MATCH:<pattern> <file>",
+"  \\farraylook(<pattern>,<arrayname>)",
+"  \\fsearch(<pattern>,<string>[,<offset>])",
+"  \\frsearch(<pattern>,<string>[,<offset>])",
+"  The /EXCEPT: clause in SEND, GET, DELETE, etc.",
+" ",
+"Example:",
+"  \\fsearch(abc,xxabcxxx) succeeds because xxabcxx contains abc.",
+"  \\fsearch(^abc,xxabcxx) fails because xxabcxx does not start with abc.",
+" ",
+"All other commands and functions that use patterns use anchored patterns,",
+"meaning that ^ and $ are not treated specially, and * is not assumed at the",
+"beginning or end of the pattern.  This is true mainly of filename patterns",
+"(wildcards), since you would not want a command like \"delete x\" to delete",
+"all files whose names contained \"x\"!",
+" ",
+"You can use anchored patterns not only in filenames, but also in SWITCH",
+"case labels, in the INPUT and MINPUT commands, and in file binary- and",
+"text-patterns for filenames.  The IF MATCH pattern is also anchored.",
+#endif /* NOSPL */
+"" };
+
+static char *hmxxwild[] = {
+
+"A \"wildcard\" is a notation used in a filename to match multiple files.",
+"For example, in \"send *.txt\" the asterisk is a wildcard.  Kermit commands",
+"that accept filenames also accepts wildcards, except commands that are",
+"allowed to operate on only one file, such as TRANSMIT.",
+"This version of Kermit accepts the following wildcards:",
+" ",
+"* Matches any sequence of zero or more characters.  For example, \"ck*.c\"",
+"  matches all files whose names start with \"ck\" and end with \".c\"",
+"  including \"ck.c\".",
+" ",
+#ifdef VMS
+"% Matches any single character.  For example, \"ck%.c\" matches all files",
+#else
+"? Matches any single character.  For example, \"ck?.c\" matches all files",
+#endif /* VMS */
+"  whose names are exactly 5 characters long and start with \"ck\" and end",
+#ifdef VMS
+"  with \".c\".",
+#else
+"  with \".c\".  When typing commands at the prompt, you must precede any",
+"  question mark to be used for matching by a backslash (\\) to override the",
+"  normal function of question mark, which is providing menus and file lists.",
+#endif /* VMS */
+" ",
+#ifdef OS2ORUNIX
+#ifdef CKREGEX
+"[abc]",
+"  Square brackets enclosing a list of characters matches any character in",
+"  the list.  Example: ckuusr.[ch] matches ckuusr.c and ckuusr.h.",
+" ",
+"[a-z]",
+"  Square brackets enclosing a range of characters matches any character in",
+"  the range; a hyphen (-) separates the low and high elements of the range.",
+"  For example, [a-z] matches any character from a to z.",
+" ",
+"[acdm-z]",
+"  Lists and ranges may be combined.  This example matches a, c, d, or any",
+"  letter from m through z.",
+" ",
+"{string1,string2,...}",
+"  Braces enclose a list of strings to be matched.  For example:",
+"  ck{ufio,vcon,cmai}.c matches ckufio.c, ckvcon.c, or ckcmai.c.  The strings",
+"  may themselves contain *, ?, [abc], [a-z], or other lists of strings.",
+#endif /* CKREGEX */
+#endif /* OS2ORUNIX */
+" ",
+"To force a special pattern character to be taken literally, precede it with",
+"a backslash, e.g. [a\\-z] matches a, hyphen, and z rather than a through z.",
+" ",
+#ifndef NOSPL
+"Similar notation can be used in general-purpose string matching.  Type HELP",
+"PATTERNS for details.  Also see HELP SET MATCH.",
+#endif /* NOSPL */
+"" };
+
+#ifndef NOXFER
+static char *hmxxfast[] = {
+"FAST, CAUTIOUS, and ROBUST are predefined macros that set several",
+"file-transfer parameters at once to achieve the desired file-transfer goal.",
+"FAST chooses a large packet size, a large window size, and a fair amount of",
+"control-character unprefixing at the risk of possible failure on some",
+"connections.  FAST is the default tuning in C-Kermit 7.0 and later.  In case",
+"FAST file transfers fail for you on a particular connection, try CAUTIOUS.",
+"If that fails too, try ROBUST.  You can also change the definitions of each",
+"macro with the DEFINE command.  To see the current definitions, type",
+"\"show macro fast\", \"show macro cautious\", or \"show macro robust\".",
+""
+};
+#endif /* NOXFER */
+
+#ifdef VMS
+static char * hmxxpurge[] = {
+"Syntax: PURGE [ switches ] [ filespec ]",
+"  Runs the DCL PURGE command.  Switches and filespec are not parsed or",
+"  verified by Kermit, but passed directly to DCL.",
+""
+};
+#else
+#ifdef CKPURGE
+static char * hmxxpurge[] = {
+"Syntax: PURGE [ switches ] [ filespec ]",
+"  Deletes backup files; that is, files whose names end in \".~n~\", where",
+"  n is a number.  PURGE by itself deletes all backup files in the current",
+"  directory.  Switches:",
+
+" ",
+"/AFTER:date-time",
+#ifdef VMS
+"  Specifies that only those files created after the given date-time are",
+#else
+"  Specifies that only those files modified after the given date-time are",
+#endif /* VMS */
+"  to be purged.  HELP DATE for info about date-time formats.",
+" ",
+"/BEFORE:date-time",
+#ifdef VMS
+"  Specifies that only those files modified before the given date-time",
+#else
+"  Specifies that only those files modified before the given date-time",
+#endif /* VMS */
+"  are to be purged.",
+" ",
+"/NOT-AFTER:date-time",
+#ifdef VMS
+"  Specifies that only those files modified at or before the given date-time",
+#else
+"  Specifies that only those files modified at or before the given date-time",
+#endif /* VMS */
+"  are to be purged.",
+" ",
+"/NOT-BEFORE:date-time",
+#ifdef VMS
+"  Specifies that only those files modified at or after the given date-time",
+#else
+"  Specifies that only those files modified at or after the given date-time",
+#endif /* VMS */
+"  are to be purged.",
+" ",
+"/LARGER-THAN:number",
+"  Specifies that only those files longer than the given number of bytes are",
+"  to be purged.",
+" ",
+"/SMALLER-THAN:number",
+"  Specifies that only those files smaller than the given number of bytes are",
+"  to be purged.",
+" ",
+"/EXCEPT:pattern",
+"  Specifies that any files whose names match the pattern, which can be a",
+"  regular filename or may contain wildcards, are not to be purged.  To",
+"  specify multiple patterns (up to 8), use outer braces around the group",
+"  and inner braces around each pattern:",
+" ",
+"    /EXCEPT:{{pattern1}{pattern2}...}",
+" ",
+#ifdef UNIXOROSK
+"/DOTFILES",
+"  Include (purge) files whose names begin with \".\".",
+" ",
+"/NODOTFILES",
+"  Skip (don't purge) files whose names begin with \".\".",
+" ",
+#endif /* UNIXOROSK */
+#ifdef RECURSIVE
+"/RECURSIVE",
+"  Descends through the current or specified directory tree.",
+" ",
+#endif /* RECURSIVE */
+"/KEEP:n",
+"  Retain the 'n' most recent (highest-numbered) backup files for each file.",
+"  By default, none are kept.  If /KEEP is given without a number, 1 is used.",
+" ",
+"/LIST",
+"  Display each file as it is processed and say whether it is purged or kept.",
+"  Synonyms: /LOG, /VERBOSE.",
+" ",
+"/NOLIST",
+"  The PURGE command should operate silently (default).",
+"  Synonyms: /NOLOG, /QUIET.",
+" ",
+"/HEADING",
+"  Print heading and summary information.",
+" ",
+"/NOHEADING",
+"  Don't print heading and summary information.",
+" ",
+"/PAGE",
+"  When /LIST is in effect, pause at the end of each screenful, even if",
+"  COMMAND MORE-PROMPTING is OFF.",
+" ",
+"/NOPAGE",
+"  Don't pause, even if COMMAND MORE-PROMPTING is ON.",
+" ",
+"/ASK",
+"  Interactively ask permission to delete each backup file.",
+" ",
+"/NOASK",
+"  Purge backup files without asking permission.",
+" ",
+"/SIMULATE",
+"  Inhibits the actual deletion of files; use to preview which files would",
+"  actually be deleted.  Implies /LIST.",
+" ",
+"Use SET OPTIONS PURGE [ switches ] to change defaults; use SHOW OPTIONS to",
+"display customized defaults.  Also see HELP DELETE, HELP WILDCARD.",
+""
+};
+#endif /* CKPURGE */
+#endif /* VMS */
+
+static char *hmxxclo[] = {
+"Syntax:  CLOSE [ item ]",
+"  Close the indicated item.  The default item is CONNECTION, which is the",
+"  current SET LINE or SET HOST connection.  The other items are:",
+" ",
+#ifdef CKLOGDIAL
+"    CX-LOG          (connection log, opened with LOG CX)",
+#endif /* CKLOGDIAL */
+#ifndef NOLOCAL
+"    SESSION-LOG     (opened with LOG SESSION)",
+#endif /* NOLOCAL */
+#ifdef TLOG
+"    TRANSACTION-LOG (opened with LOG TRANSACTIONS)",
+#endif /* TLOG */
+"    PACKET-LOG      (opened with LOG PACKETS)",
+#ifdef DEBUG
+"    DEBUG-LOG       (opened with LOG DEBUG)",
+#endif /* DEBUG */
+#ifndef NOSPL
+"    READ-FILE       (opened with OPEN READ)",
+"    WRITE-FILE      (opened with OPEN WRITE or OPEN APPEND)",
+#endif /* NOSPL */
+" ",
+"Type HELP LOG and HELP OPEN for further info.",
+""
+};
+
+#ifdef CKLEARN
+static char * hmxxlearn[] = {
+"Syntax: LEARN [ /ON /OFF /CLOSE ] [ filename ]",
+"  Records a login script.  If you give a filename, the file is opened for",
+"  subsequent recording.  If you don't give any switches, /ON is assumed.",
+"  /ON enables recording to the current file (if any); /OFF disables",
+"  recording.  /CLOSE closes the current file (if any).  After LEARN /CLOSE",
+"  or exit from Kermit, your script is available for execution by the TAKE",
+"  command.",
+""
+};
+#endif /* CKLEARN */
+
+#ifdef CK_MINPUT
+static char *hmxxminp[] = {
+"Syntax:  MINPUT n [ string1 [ string2 [ ... ] ] ]",
+"Example: MINPUT 5 Login: {Username: } {NO CARRIER} BUSY RING",
+"  For use in script programs.  Waits up to n seconds for any one of the",
+"  strings to arrive on the communication device.  If no strings are given,",
+"  the command waits for any character at all to arrive.  Strings are",
+"  separated by spaces; use { braces } for grouping.  If any of the strings",
+"  is encountered within the timeout interval, the command succeeds and the",
+"  \\v(minput) variable is set to the number of the string that was matched:",
+"  1, 2, 3, etc.  If none of the strings arrives, the command times out,",
+"  fails, and \\v(minput) is set to 0.  If the timeout interval is 0 the",
+"  MINPUT command does not wait; i.e. the given text must already be",
+"  available for reading for the MINPUT command to succeed.  If the interval",
+"  is negative, the MINPUT command waits forever.",
+" ",
+"Also see: INPUT, REINPUT, SET INPUT.",
+"" };
+#endif /* CK_MINPUT */
+
+#ifndef NOLOCAL
+static char *hmxxcon[] = {
+"Syntax: CONNECT (or C, or CQ) [ switches ]",
+"  Connect to a remote computer via the serial communications device given in",
+#ifdef OS2
+"  the most recent SET PORT command, or to the network host named in the most",
+#else
+"  the most recent SET LINE command, or to the network host named in the most",
+#endif /* OS2 */
+"  recent SET HOST command.  Type the escape character followed by C to get",
+"  back to the C-Kermit prompt, or followed by ? for a list of CONNECT-mode",
+#ifdef OS2
+"  escape commands.  You can also assign the \\Kexit verb to the key or",
+"  key-combination of your choice; by default it is assigned to Alt-x.",
+#else
+"  escape commands.",
+" ",
+"Include the /QUIETLY switch to suppress the informational message that",
+"tells you how to escape back, etc.  CQ is a synonym for CONNECT /QUIETLY.",
+#endif /* OS2 */
+" ",
+"Other switches include:",
+#ifdef CK_TRIGGER
+" ",
+"/TRIGGER:string",
+"  One or more strings to look for that will cause automatic return to",
+"  command mode.  To specify one string, just put it right after the",
+"  colon, e.g. \"/TRIGGER:Goodbye\".  If the string contains any spaces, you",
+"  must enclose it in braces, e.g. \"/TRIGGER:{READY TO SEND...}\".  To",
+"  specify more than one trigger, use the following format:",
+" ",
+"    /TRIGGER:{{string1}{string2}...{stringn}}",
+" ",
+"  Upon return from CONNECT mode, the variable \\v(trigger) is set to the",
+"  trigger string, if any, that was actually encountered.  This value, like",
+"  all other CONNECT switches applies only to the CONNECT command with which",
+"  it is given, and overrides (temporarily) any global SET TERMINAL TRIGGER",
+"  string that might be in effect.",
+#endif /* CK_TRIGGER */
+#ifdef OS2
+" ",
+"/IDLE-LIMIT:number",
+"  The number of seconds of idle time, after which Kermit returns",
+"  automatically to command mode; default 0 (no limit).",
+" ",
+"/IDLE-INTERVAL:number",
+"  The number of seconds of idle time, after which Kermit automatically",
+"  transmits the idle string.",
+" ",
+"/IDLE-STRING:string",
+"  The string to transmit whenever the idle interval has passed.",
+" ",
+"/TIME-LIMIT:number",
+"  The maximum number of seconds for which the CONNECT session may last.",
+"  The default is 0 (no limit).  If a nonzero number is given, Kermit returns",
+"  automatically to command mode after this many seconds.",
+#endif /* OS2 */
+"" };
+#endif /* NOLOCAL */
+
+static char *hmxxmget[] = {
+"Syntax: MGET [ switches... ] remote-filespec [ remote-filespec ... ]",
+" ",
+"Just like GET (q.v.) except allows a list of remote file specifications,",
+"separated by spaces.",
+""
+};
+
+static char *hmxxget[] = {
+"Syntax: GET [ switches... ] remote-filespec [ as-name ]",
+"  Tells the other Kermit, which must be in (or support autoswitching into)",
+"  server mode, to send the named file or files.  If the remote-filespec or",
+"  the as-name contain spaces, they must be enclosed in braces.  If as-name",
+"  is the name of an existing local directory, incoming files are placed in",
+"  that directory; if it is the name of directory that does not exist, Kermit",
+"  tries to create it.  Optional switches include:",
+" ",
+"/AS-NAME:text",
+"  Specifies \"text\" as the name to store the incoming file under, or",
+"  directory to store it in.  You can also specify the as-name as the second",
+"  filename on the GET command line.",
+" ",
+"/BINARY",
+"  Performs this transfer in binary mode without affecting the global",
+"  transfer mode.",
+" ",
+"/COMMAND",
+"  Receives the file into the standard input of a command, rather than saving",
+"  it on  disk.  The /AS-NAME or the second \"filename\" on the GET command",
+"  line is interpreted as the name of a command.",
+" ",
+"/DELETE",
+"  Asks the other Kermit to delete the file (or each file in the group)",
+"  after it has been transferred successfully.",
+" ",
+"/EXCEPT:pattern",
+"  Specifies that any files whose names match the pattern, which can be a",
+"  regular filename, or may contain \"*\" and/or \"?\" metacharacters,",
+"  are to be refused.  To specify multiple patterns (up to 8), use outer",
+"  braces around the group, and inner braces around each pattern:",
+" ",
+"    /EXCEPT:{{pattern1}{pattern2}...}",
+" ",
+"/FILENAMES:{CONVERTED,LITERAL}",
+"  Overrides the global SET FILE NAMES setting for this transfer only.",
+" ",
+"/FILTER:command",
+"  Causes the incoming file to passed through the given command (standard",
+"  input/output filter) before being written to disk.",
+" ",
+#ifdef VMS
+"/IMAGE",
+"  Transfer in image mode.",
+" ",
+#endif /* VMS */
+#ifdef CK_LABELED
+"/LABELED",
+"  VMS and OS/2 only: Specifies labeled transfer mode.",
+" ",
+#endif /* CK_LABELED */
+
+"/MOVE-TO:directory-name",
+"  Specifies that each file that arrives should be moved to the specified",
+"  directory after, and only if, it has been received successfully.",
+" ",
+"/PATHNAMES:{OFF,ABSOLUTE,RELATIVE,AUTO}",
+"  Overrides the global SET RECEIVE PATHNAMES setting for this transfer.",
+" ",
+"/PIPES:{ON,OFF}",
+"  Overrides the TRANSFER PIPES setting for this command only.  ON allows",
+"  reception of files with names like \"!tar xf -\" to be automatically",
+"  directed to a pipeline.",
+" ",
+"/QUIET",
+"  When sending in local mode, this suppresses the file-transfer display.",
+" ",
+"/RECOVER",
+"  Used to recover from a previously interrupted transfer; GET /RECOVER",
+"  is equivalent REGET.  Works only in binary mode.",
+" ",
+"/RECURSIVE",
+"  Tells the server to descend through the directory tree when locating",
+"  the files to be sent.",
+" ",
+"/RENAME-TO:string",
+"  Specifies that each file that arrives should be renamed as specified",
+"  after, and only if, it has been received successfully.  The string should",
+"  normally contain variables like \\v(filename) or \\v(filenum).",
+" ",
+"/TEXT",
+"  Performs this transfer in text mode without affecting the global",
+"  transfer mode.",
+" ",
+"/TRANSPARENT",
+"  Inhibits character-set translation of incoming text files for the duration",
+"  of the GET command without affecting subsequent commands.",
+" ",
+"Also see HELP MGET, HELP SEND, HELP RECEIVE, HELP SERVER, HELP REMOTE.",
+""};
+
+static char *hmxxlg[] = {
+"Syntax: LOG (or L) log-type [ filename [ { NEW, APPEND } ] ]",
+" ",
+"Record information in a log file:",
+" ",
+#ifdef CKLOGDIAL
+"CX",
+"  Connections made with SET LINE, SET PORT, SET HOST, DIAL, TELNET, etc.",
+"  The default filename is CX.LOG in your home directory and APPEND is the",
+"  default mode for opening.",
+" ",
+#endif /* CKLOGDIAL */
+#ifdef DEBUG
+"DEBUG",
+"  Debugging information, to help track down bugs in the C-Kermit program.",
+"  The default log name is debug.log in current directory.",
+" ",
+#endif /* DEBUG */
+"PACKETS",
+"  Kermit packets, to help with protocol problems.  The default filename is",
+"  packet.log in current directory.",
+" ",
+#ifndef NOLOCAL
+"SESSION",
+"  Records your CONNECT session (default: session.log in current directory).",
+" ",
+#endif /* NOLOCAL */
+#ifdef TLOG
+"TRANSACTIONS",
+"  Names and statistics about files transferred (default: transact.log in",
+"  current directory; see HELP SET TRANSACTION-LOG for transaction-log format",
+"  options.)",
+" ",
+#endif /* TLOG */
+"If you include the APPEND keyword after the filename, the existing log file,",
+"if any, is appended to; otherwise a new file is created (except APPEND is",
+"the default for the connection log).  Use CLOSE <keyword> to stop logging.",
+#ifdef OS2ORUNIX
+" ",
+"Note: The filename can also be a pipe, e.g.:",
+" ",
+"  log transactions |lpr",
+"  log debug {| grep \"^TELNET\" > debug.log}",
+" ",
+"Braces are required if the pipeline or filename contains spaces.",
+#endif /* OS2ORUNIX */
+"" };
+
+#ifndef NOSCRIPT
+static char *hmxxlogi[] = { "\
+Syntax: SCRIPT text",
+"  A limited and cryptic \"login assistant\", carried over from old C-Kermit",
+"  releases for comptability, but not recommended for use.  Instead, please",
+"  use the full script programming language described in chapters 17-19 of",
+"  \"Using C-Kermit\".",
+" ",
+"  Login to a remote system using the text provided.  The login script",
+"  is intended to operate similarly to UNIX uucp \"L.sys\" entries.",
+"  A login script is a sequence of the form:",
+" ",
+"    expect send [expect send] . . .",
+" ",
+"  where 'expect' is a prompt or message to be issued by the remote site, and",
+"  'send' is the names, numbers, etc, to return.  The send may also be the",
+"  keyword EOT to send Control-D, or BREAK (or \\\\b) to send a break signal.",
+"  Letters in send may be prefixed by ~ to send special characters:",
+" ",
+"  ~b backspace, ~s space, ~q '?', ~n linefeed, ~r return, ~c don\'t",
+"  append a return, and ~o[o[o]] for octal of a character.  As with some",
+"  UUCP systems, sent strings are followed by ~r unless they end with ~c.",
+" ",
+"  Only the last 7 characters in each expect are matched.  A null expect,",
+"  e.g. ~0 or two adjacent dashes, causes a short delay.  If you expect",
+"  that a sequence might not arrive, as with uucp, conditional sequences",
+"  may be expressed in the form:",
+" ",
+"    -send-expect[-send-expect[...]]",
+" ",
+"  where dashed sequences are followed as long as previous expects fail.",
+"" };
+#endif /* NOSCRIPT */
+
+#ifndef NOFRILLS
+static char * hmxxtyp[] = {
+"Syntax: TYPE [ switches... ] file",
+"  Displays a file on the screen.  Pauses automatically at end of each",
+"  screenful if COMMAND MORE-PROMPTING is ON.  Optional switches:",
+" ",
+"  /PAGE",
+"     Pause at the end of each screenful even if COMMAND MORE-PROMPTING OFF.",
+"     Synonym: /MORE",
+"  /NOPAGE",
+"     Don't pause at the end of each screen even if COMMAND MORE-PROMPTING ON."
+,
+"  /HEAD:n",
+"     Only type the first 'n' lines of the file.",
+"  /TAIL:n",
+"     Only type the last 'n' lines of the file.",
+"  /MATCH:pattern",
+"     Only type lines that match the given pattern.  HELP WILDCARDS for info",
+"     info about patterns.  /HEAD and /TAIL apply after /MATCH.",
+"  /PREFIX:string",
+"     Print the given string at the beginning of each line.",
+"  /NUMBER",
+"     Add line numbers (conflicts with /PREFIX)",
+"  /WIDTH:number",
+"     Truncate each line at the given column number before printing.",
+#ifdef KUI
+"     Or when combined with /GUI specifies the width of the dialog box.",
+"  /HEIGHT:number",
+"     When combined with /GUI specifies the height of the dialog box.",
+"  /GUI:string",
+"     Specifies the title to use for the dialog box.",
+#endif /* KUI */
+"  /COUNT",
+"     Count lines (and matches) and print the count(s) but not the lines.",
+#ifdef UNICODE
+"  /CHARACTER-SET:name",
+"     Translates from the named character set.",
+#ifndef OS2
+"  /TRANSLATE-TO:name",
+"     Translates to the named character set (default = current file charset).",
+#endif /* OS2 */
+"  /TRANSPARENT",
+"     Inhibits character-set translation.",
+#endif /* UNICODE */
+"  /OUTPUT:name",
+"     Sends results to the given file.  If this switch is omitted, the",
+"     results appear on your screen.  This switch overrides any express or",
+"     implied /PAGE switch.",
+" ",
+"You can use SET OPTIONS TYPE to set the defaults for /PAGE or /NOPAGE and",
+"/WIDTH.  Use SHOW OPTIONS to see current TYPE options.",
+""
+};
+
+static char * hmxxcle[] = {
+"Syntax: CLEAR [ item-name ]",
+" ",
+"Clears the named item.  If no item is named, DEVICE-AND-INPUT is assumed.",
+" ",
+"  ALARM            Clears any pending alarm (see SET ALARM).",
+#ifdef CK_APC
+"  APC-STATUS       Clears Application Program Command status.",
+#endif /* CK_APC */
+#ifdef PATTERNS
+"  BINARY-PATTERNS  Clears the file binary-patterns list.",
+#endif /* PATTERNS */
+#ifdef OS2
+"  COMMAND-SCREEN   Clears the current command screen.",
+#endif /* OS2 */
+"  DEVICE           Clears the current port or network input buffer.",
+"  DEVICE-AND-INPUT Clears both the device and the INPUT buffer.",
+"  DIAL-STATUS      Clears the \\v(dialstatus) variable.",
+"  \
+INPUT            Clears the INPUT-command buffer and the \\v(input) variable.",
+"  KEYBOARD-BUFFER  Clears the command terminal keyboard input buffer.",
+#ifdef OS2
+"  \
+SCROLLBACK       empties the scrollback buffer including the current screen.",
+#endif /* OS2 */
+"  SEND-LIST        Clears the current SEND list (see ADD).",
+#ifdef OS2
+"  \
+TERMINAL-SCREEN  Clears the current screen a places it into the scrollback.",
+"    buffer.",
+#endif /* OS2 */
+#ifdef PATTERNS
+"  TEXT-PATTERNS    Clears the file text-patterns list.",
+#endif /* PATTERNS */
+""};
+#endif /* NOFRILLS */
+
+static char * hmxxdate[] = {
+"Syntax: DATE [ date-time [ timezone ] ] [ delta-time ]",
+"  Prints a date-time in standard format: yyyymmdd_hh:mm:ss.",
+"  Various date-time formats are accepted:",
+" ",
+"  . The date, if given, must precede the time.",
+"  . The year must be four digits or else a 2-digit format dd mmm yy,",
+"    in which case if (yy < 50) yyyy = yy + 2000; else yyyy = yy + 1900.",
+"  . If the year comes first, the second field is the month.",
+"  . The day, month, and year may be separated by spaces, /, -, or underscore."
+,"  . The date and time may be separated by spaces or underscore.",
+"  . The month may be numeric (1 = January) or spelled out or abbreviated in",
+"    English.",
+"  . The time may be in 24-hour format or 12-hour format.",
+"  . If the hour is 12 or less, AM is assumed unless AM or PM is included.",
+"  . If the date is omitted but a time is given, the current date is supplied."
+,
+"  . If the time is given but date omitted, 00:00:00 is supplied.",
+"  . If both the date and time are omitted, the current date and time are",
+"    supplied.",
+" ",
+"  The following shortcuts can also be used in place of dates:",
+" ",
+"  TODAY",
+"    Today's date, optionally followed by a time; 00:00:00 if no time given.",
+" ",
+"  YESTERDAY",
+"    Yesterday's date, optionally followed by a time (default 00:00:00).",
+" ",
+"  TOMORROW",
+"    Tomorrows's date, optionally followed by a time (default 00:00:00).",
+" ",
+"  Timezone specifications are similar to those used in e-mail and HTTP",
+"    headers, either a USA timezone name, e.g. EST or a signed four-digit",
+"    timezone offset, {+,-}hhmm, e.g., -0500; it is used to convert date-time,"
+,
+"    a local time in that timezone, to GMT which is then converted to the",
+"    local time at the host.  If no timezone is given, the date-time is local."
+,
+" ",
+"  Delta times are given as {+,-}[number date-units][hh[:mm[:ss]]]",
+"    A date in the future/past relative to the date-time; date-units may be",
+"    DAYS, WEEKS, MONTHS, YEARS: +3days, -7weeks, +3:00, +1month 8:00.",
+" ",
+"All the formats shown above are acceptable as arguments to date-time switches"
+,
+"such as /AFTER: or /BEFORE:, and to functions such as \\fcvtdate(),",
+"\\fdiffdate(), and \\futcdate(), that take date-time strings as arguments.",
+""
+};
+
+
+#ifndef NOXFER
+static char * hmxxsen[] = {
+"Syntax: SEND (or S) [ switches...] [ filespec [ as-name ] ]",
+"  Sends the file or files specified by filespec.  If the filespec is omitted",
+"  the SEND-LIST is used (HELP ADD for more info).  The filespec may contain",
+"  wildcard characters.  An 'as-name' may be given to specify the name(s)",
+"  the files(s) are sent under; if the as-name is omitted, each file is",
+"  sent under its own name.  Also see HELP MSEND, HELP WILDCARD.",
+"  Optional switches include:",
+" ",
+#ifndef NOSPL
+"/ARRAY:<arrayname>",
+"  Specifies that the data to be sent comes from the given array, such as",
+"  \\&a[].  A range may be specified, e.g. SEND /ARRAY:&a[100:199].  Leave",
+"  the brackets empty or omit them altogether to send the whole 1-based array."
+,
+"  Include /TEXT to have Kermit supply a line terminator at the end of each",
+"  array element (and translate character sets if character-set translations",
+"  are set up), or /BINARY to treat the array as one long string of characters"
+,
+"  to be sent as-is.  If an as-name is not specified, the array is sent with",
+"  the name _ARRAY_X_, where \"X\" is replaced by actual array letter.",
+" ",
+#endif /* NOSPL */
+
+"/AS-NAME:<text>",
+"  Specifies <text> as the name to send the file under instead of its real",
+"  name.  This is equivalent to giving an as-name after the filespec.",
+" ",
+"/BINARY",
+"  Performs this transfer in binary mode without affecting the global",
+"  transfer mode.",
+" ",
+"/TEXT",
+"  Performs this transfer in text mode without affecting the global",
+"  transfer mode.",
+" ",
+"/TRANSPARENT",
+"  Inhibits character-set translation for text files for the duration of",
+"  the SEND command without affecting subsequent commands.",
+" ",
+"/NOBACKUPFILES",
+"  Skip (don't send) Kermit or EMACS backup files (files with names that",
+"  end with .~n~, where n is a number).",
+" ",
+#ifdef UNIXOROSK
+"/DOTFILES",
+"  Include (send) files whose names begin with \".\".",
+" ",
+"/NODOTFILES",
+"  Don't send files whose names begin with \".\".",
+" ",
+"/FOLLOWLINKS",
+"  Send files that are pointed to by symbolic links.",
+" ",
+"/NOFOLLOWLINKS",
+"  Skip over symbolic links (default).",
+" ",
+#endif /* UNIXOROSK */
+
+#ifdef VMS
+"/IMAGE",
+"  Performs this transfer in image mode without affecting the global",
+"  transfer mode.",
+" ",
+#endif /* VMS */
+#ifdef CK_LABELED
+"/LABELED",
+"  Performs this transfer in labeled mode without affecting the global",
+"  transfer mode.",
+" ",
+#endif /* CK_LABELED */
+"/COMMAND",
+"  Sends the output from a command, rather than the contents of a file.",
+"  The first \"filename\" on the SEND command line is interpreted as the name",
+"  of a command; the second (if any) is the as-name.",
+" ",
+"/FILENAMES:{CONVERTED,LITERAL}",
+"  Overrides the global SET FILE NAMES setting for this transfer only.",
+" ",
+"/PATHNAMES:{OFF,ABSOLUTE,RELATIVE}",
+"  Overrides the global SET SEND PATHNAMES setting for this transfer.",
+" ",
+"/FILTER:command",
+"  Specifies a command \
+(standard input/output filter) to pass the file through",
+"  before sending it.",
+" ",
+"/DELETE",
+"  Deletes the file (or each file in the group) after it has been sent",
+"  successfully (applies only to real files).",
+" ",
+"/QUIET",
+"  When sending in local mode, this suppresses the file-transfer display.",
+" ",
+"/RECOVER",
+"  Used to recover from a previously interrupted transfer; SEND /RECOVER",
+"  is equivalent RESEND (use in binary mode only).",
+" ",
+"/RECURSIVE",
+"  Tells C-Kermit to look not only in the given or current directory for",
+"  files that match the filespec, but also in all its subdirectories, and",
+"  all their subdirectories, etc.",
+" ",
+"/RENAME-TO:name",
+"  Tells C-Kermit to rename each source file that is sent successfully to",
+"  the given name (usually you should include \\v(filename) in the new name,",
+"  which is replaced by the original filename.",
+" ",
+"/MOVE-TO:directory",
+"  Tells C-Kermit to move each source file that is sent successfully to",
+"  the given directory.",
+" ",
+"/STARTING:number",
+"  Starts sending the file from the given byte position.",
+"  SEND /STARTING:n filename is equivalent to PSEND filename n.",
+" ",
+"/SUBJECT:text",
+"  Specifies the subject of an email message, to be used with /MAIL.  If the",
+"  text contains spaces, it must be enclosed in braces.",
+" ",
+"/MAIL:address",
+"  Sends the file as e-mail to the given address; use with /SUBJECT:.",
+" ",
+"/PRINT:options",
+"  Sends the file to be printed, with optional options for the printer.",
+" ",
+#ifdef CK_XYZ
+"/PROTOCOL:name",
+"  Uses the given protocol to send the file (Kermit, Zmodem, etc) for this",
+"  transfer without changing global protocol.",
+" ",
+#endif /* CK_XYZ */
+"/AFTER:date-time",
+#ifdef VMS
+"  Specifies that only those files created after the given date-time are",
+#else
+"  Specifies that only those files modified after the given date-time are",
+#endif /* VMS */
+"  to be sent.  HELP DATE for info about date-time formats.",
+" ",
+"/BEFORE:date-time",
+#ifdef VMS
+"  Specifies that only those files modified before the given date-time",
+#else
+"  Specifies that only those files modified before the given date-time",
+#endif /* VMS */
+"  are to be sent.",
+" ",
+"/NOT-AFTER:date-time",
+#ifdef VMS
+"  Specifies that only those files modified at or before the given date-time",
+#else
+"  Specifies that only those files modified at or before the given date-time",
+#endif /* VMS */
+"  are to be sent.",
+" ",
+"/NOT-BEFORE:date-time",
+#ifdef VMS
+"  Specifies that only those files modified at or after the given date-time",
+#else
+"  Specifies that only those files modified at or after the given date-time",
+#endif /* VMS */
+"  are to be sent.",
+" ",
+"/LARGER-THAN:number",
+"  Specifies that only those files longer than the given number of bytes are",
+"  to be sent.",
+" ",
+"/SMALLER-THAN:number",
+"  Specifies that only those files smaller than the given number of bytes are",
+"  to be sent.",
+" ",
+"/EXCEPT:pattern",
+"  Specifies that any files whose names match the pattern, which can be a",
+"  regular filename, or may contain \"*\" and/or \"?\" metacharacters,",
+"  are not to be sent.  To specify multiple patterns (up to 8), use outer",
+"  braces around the group, and inner braces around each pattern:",
+" ",
+"    /EXCEPT:{{pattern1}{pattern2}...}",
+" ",
+"/TYPE:{ALL,TEXT,BINARY}",
+"  Send only files of the given type (see SET FILE SCAN).",
+" ",
+"/LISTFILE:filename",
+"  Specifies the name of a file that contains the list of names of files",
+"  that are to be sent.  The filenames should be listed one name per line",
+"  in this file (but a name can contain wildcards).",
+" ",
+"Also see HELP RECEIVE, HELP GET, HELP SERVER, HELP REMOTE.",
+""};
+
+static char *hmxxrc[] = {
+"Syntax: RECEIVE (or R) [ switches... ] [ as-name ]",
+"  Wait for a file to arrive from the other Kermit, which must be given a",
+"  SEND command.  If the optional as-name is given, the incoming file or",
+"  files are stored under that name, otherwise it will be stored under",
+#ifndef CK_TMPDIR
+"  the name it arrives with.",
+#else
+#ifdef OS2
+"  the name it arrives with.  If the filespec denotes a disk and/or",
+"  directory, the incoming file or files will be stored there.",
+#else
+"  the name it arrives with.  If the filespec denotes a directory, the",
+"  incoming file or files will be placed in that directory.",
+#endif /* OS2 */
+#endif /* CK_TMPDIR */
+" ",
+"Optional switches include:",
+" ",
+"/AS-NAME:text",
+"  Specifies \"text\" as the name to store the incoming file under.",
+"  You can also specify the as-name as a filename on the command line.",
+" ",
+"/BINARY",
+"  Skips text-mode conversions unless the incoming file arrives with binary",
+"  attribute",
+" ",
+"/COMMAND",
+"  Receives the file into the standard input of a command, rather than saving",
+"  it on disk.  The /AS-NAME or the \"filename\" on the RECEIVE command line",
+"  is interpreted as the name of a command.",
+" ",
+"/EXCEPT:pattern",
+"  Specifies that any files whose names match the pattern, which can be a",
+"  regular filename, or may contain \"*\" and/or \"?\" metacharacters,",
+"  are to be refused.  To specify multiple patterns (up to 8), use outer",
+"  braces around the group, and inner braces around each pattern:",
+" ",
+"    /EXCEPT:{{pattern1}{pattern2}...}",
+" ",
+"/FILENAMES:{CONVERTED,LITERAL}",
+"  Overrides the global SET FILE NAMES setting for this transfer only.",
+" ",
+"/FILTER:command",
+"  Causes the incoming file to passed through the given command (standard",
+"  input/output filter) before being written to disk.",
+" ",
+#ifdef VMS
+"/IMAGE",
+"  Receives the file in image mode.",
+" ",
+#endif /* VMS */
+#ifdef CK_LABELED
+"/LABELED",
+"  Specifies labeled transfer mode.",
+" ",
+#endif /* CK_LABELED */
+
+"/MOVE-TO:directory-name",
+"  Specifies that each file that arrives should be moved to the specified",
+"  directory after, and only if, it has been received successfully.",
+" ",
+"/PATHNAMES:{OFF,ABSOLUTE,RELATIVE,AUTO}",
+"  Overrides the global SET RECEIVE PATHNAMES setting for this transfer.",
+" ",
+"/PIPES:{ON,OFF}",
+"  Overrides the TRANSFER PIPES setting for this command only.  ON allows",
+"  reception of files with names like \"!tar xf -\" to be automatically",
+"  directed to a pipeline.",
+" ",
+"/PROTOCOL:name",
+"  Use the given protocol to receive the incoming file(s).",
+" ",
+"/QUIET",
+"  When sending in local mode, this suppresses the file-transfer display.",
+" ",
+"/RECURSIVE",
+"  Equivalent to /PATHNAMES:RELATIVE.",
+" ",
+"/RENAME-TO:string",
+"  Specifies that each file that arrives should be renamed as specified",
+"  after, and only if, it has been received successfully.  The string should",
+"  normally contain variables like \\v(filename) or \\v(filenum).",
+" ",
+"/TEXT",
+"  Forces text-mode conversions unless the incoming file has the binary",
+"  attribute",
+" ",
+"/TRANSPARENT",
+"  Inhibits character-set translation of incoming text files for the duration",
+"  of the RECEIVE command without affecting subsequent commands.",
+" ",
+"Also see HELP SEND, HELP GET, HELP SERVER, HELP REMOTE.",
+"" };
+
+#ifndef NORESEND
+static char *hmxxrsen = "\
+Syntax: RESEND filespec [name]\n\n\
+  Resend the file or files, whose previous transfer was interrupted.\n\
+  Picks up from where previous transfer left off, IF the receiver was told\n\
+  to SET FILE INCOMPLETE KEEP.  Only works for binary-mode transfers.\n\
+  Requires the other Kermit to have RESEND capability.";
+
+static char *hmxxrget = "\
+Syntax: REGET filespec\n\n\
+  Ask a server to RESEND a file to C-Kermit.";
+
+static char *hmxxpsen = "\
+Syntax: PSEND filespec position [name]\n\n\
+  Just like SEND, except sends the file starting at the given byte position.";
+#endif /* NORESEND */
+
+#ifndef NOMSEND
+static char *hmxxmse[] = {
+"Syntax: MSEND [ switches... ] filespec [ filespec [ ... ] ]",
+"  Sends the files specified by the filespecs.  One or more filespecs may be",
+"  listed, separated by spaces.  Any or all filespecs may contain wildcards",
+"  and they may be in different directories.  Alternative names cannot be",
+"  given.  Switches include /BINARY /DELETE /MAIL /PROTOCOL /QUIET /RECOVER",
+"  /TEXT /TYPE; see HELP SEND for descriptions.",
+""
+};
+#endif /* NOMSEND */
+
+static char *hmxxadd[] = {
+#ifndef NOMSEND
+"ADD SEND-LIST filespec [ <mode> [ <as-name> ] ]",
+"  Adds the specified file or files to the current SEND list.  Use SHOW",
+"  SEND-LIST and CLEAR SEND-LIST to display and clear the list; use SEND",
+"  by itself to send the files from it.",
+" ",
+#endif /* NOMSEND */
+#ifdef PATTERNS
+"ADD BINARY-PATTERNS [ <pattern> [ <pattern> ... ] ]",
+"  Adds the pattern(s), if any, to the SET FILE BINARY-PATTERNS list.",
+" ",
+"ADD TEXT-PATTERNS [ <pattern> [ <pattern> ... ] ]",
+"  Adds the pattern(s), if any, to the SET FILE TEXT-PATTERNS list.",
+"  Use SHOW PATTERNS to see the lists.  See HELP SET FILE for further info.",
+#endif /* PATTERNS */
+""};
+
+static char *hmxxremv[] = {
+#ifdef PATTERNS
+"REMOVE BINARY-PATTERNS [ <pattern> [ <pattern> ... ] ]",
+"  Removes the pattern(s), if any, from the SET FILE BINARY-PATTERNS list",
+" ",
+"REMOVE TEXT-PATTERNS [ <pattern> [ <pattern> ... ] ]",
+"  Removes the given patterns from the SET FILE TEXT-PATTERNS list.",
+"  Use SHOW PATTERNS to see the lists.  See HELP SET FILE for further info.",
+#endif /* PATTERNS */
+""};
+#endif /* NOXFER */
+
+#ifndef NOSERVER
+static char *hmxxser = "Syntax: SERVER\n\
+  Enter server mode on the current connection.  All further commands\n\
+  are taken in packet form from the other Kermit program.  Use FINISH,\n\
+  BYE, or REMOTE EXIT to get C-Kermit out of server mode.";
+#endif /* NOSERVER */
+
+static char *hmhset[] = {
+"  The SET command establishes communication, file, scripting, or other",
+"  parameters.  The SHOW command can be used to display the values of",
+"  SET parameters.  Help is available for each individual parameter;",
+"  type HELP SET ? to see what's available.",
+"" };
+
+#ifndef NOSETKEY
+static char *hmhskey[] = {
+"Syntax: SET KEY k text",
+"Or:     SET KEY CLEAR",
+"  Configure the key whose \"scan code\" is k to send the given text when",
+"  pressed during CONNECT mode.  SET KEY CLEAR restores all the default",
+"  key mappings.  If there is no text, the default key binding is restored",
+#ifndef NOCSETS
+"  for the key k.  SET KEY mappings take place before terminal character-set",
+"  translation.",
+#else
+"  the key k.",
+#endif /* NOCSETS */
+#ifdef OS2
+" ",
+"  The text may contain \"\\Kverbs\" to denote actions, to stand for DEC",
+"  keypad, function, or editing keys, etc.  For a list of available keyboard",
+"  verbs, type SHOW KVERBS.",
+#endif /* OS2 */
+" ",
+"  To find out the scan code and mapping for a particular key, use the",
+"  SHOW KEY command.",
+""};
+#endif /* NOSETKEY */
+
+static char *hmxychkt[] = { "Syntax: SET BLOCK-CHECK type",
+" ",
+"  Type of packet block check to be used for error detection, 1, 2, 3, or",
+"  BLANK-FREE-2.  Type 1 is standard, and catches most errors.  Types 2 and 3",
+"  specify more rigorous checking at the cost of higher overhead.  The",
+"  BLANK-FREE-2 type is the same as Type 2, but is guaranteed to contain no",
+"  blanks.",
+"" };
+
+static char * hmxydeb[] = {
+"Syntax: SET DEBUG { SESSION, ON, OFF, TIMESTAMP }",
+" ",
+"SET DEBUG ON",
+#ifdef DEBUG
+"  Opens a debug log file named debug.log in the current directory.",
+"  Use LOG DEBUG if you want specify a different log file name or path.",
+#else
+"  (Has no effect in this version of Kermit.)",
+#endif /* DEBUG */
+" ",
+"SET DEBUG OFF",
+"  Stops debug logging and session debugging.",
+" ",
+"SET DEBUG SESSION",
+#ifndef NOLOCAL
+"  Displays control and 8-bit characters symbolically during CONNECT mode.",
+"  Equivalent to SET TERMINAL DEBUG ON.",
+#else
+"  (Has no effect in this version of Kermit.)",
+#endif /* NOLOCAL */
+" ",
+"SET DEBUG TIMESTAMP { ON, OFF }",
+"  Enables/Disables timestamps on debug log entries.",
+"" };
+
+#ifdef CK_SPEED
+static char *hmxyqctl[] = {
+"Syntax: SET CONTROL-CHARACTER { PREFIXED, UNPREFIXED } { <code>..., ALL }",
+" ",
+"  <code> is the numeric ASCII code for a control character 1-31,127-159,255."
+,
+"  The word \"ALL\" means all characters in this range.",
+" ",
+"  PREFIXED <code> means the given control character must be converted to a",
+"  printable character and prefixed, the default for all control characters.",
+" ",
+"  UNPREFIXED <code> means you think it is safe to send the given control",
+"  character as-is, without a prefix.  USE THIS OPTION AT YOUR OWN RISK!",
+" ",
+"  SHOW CONTROL to see current settings.  SET CONTROL PREFIXED ALL is",
+"  recommended for safety.  You can include multiple <code> values in one",
+"  command, separated by spaces.",
+"" };
+#endif /* CK_SPEED */
+
+#ifndef NODIAL
+static char *hxymodm[] = {
+"Syntax: SET MODEM <parameter> <value> ...",
+" ",
+"Note: Many of the SET MODEM parameters are configured automatically when",
+"you SET MODEM TYPE, according to the modem's capabilities.  SHOW MODEM to",
+"see them.  Also see HELP DIAL and HELP SET DIAL.",
+" ",
+"SET MODEM TYPE <name>",
+
+" Tells Kermit which kind of modem you have, so it can issue the",
+" appropriate modem-specific commands for configuration, dialing, and",
+" hanging up.  For a list of the modem types known to Kermit, type \"set",
+" modem type ?\".  The default modem type is GENERIC, which should work",
+" with any AT command-set modem that is configured for error correction,",
+" data compression, and hardware flow control.  Use SET MODEM TYPE NONE",
+" for direct serial, connections.  Use SET MODEM TYPE USER-DEFINED to use",
+" a type of modem that is not built in to Kermit, and then use SET MODEM",
+" CAPABILITIES, SET MODEM, DIAL-COMMAND, and SET MODEM COMMAND to tell",
+" Kermit how to configure and control it.",
+
+" ",
+
+"SET MODEM CAPABILITIES <list>",
+"  Use this command for changing Kermit's idea of your modem's capabilities,",
+"  for example, if your modem is supposed to have built-in error correction",
+"  but in fact does not.  Also use this command to define the capabilities",
+"  of a USER-DEFINED modem.  Capabilities are:",
+" ",
+"    AT      AT-commands",
+"    DC      data-compression",
+"    EC      error-correction",
+"    HWFC    hardware-flow",
+"    ITU     v25bis-commands",
+"    SWFC    software-flow",
+"    KS      kermit-spoof",
+"    SB      speed-buffering",
+"    TB      Telebit",
+" ",
+"SET MODEM CARRIER-WATCH { AUTO, ON, OFF }",
+"  Synonym for SET CARRIER-WATCH (q.v.)",
+" ",
+"SET MODEM COMPRESSION { ON, OFF }",
+"  Enables/disables the modem's data compression feature, if any.",
+" ",
+"SET MODEM DIAL-COMMAND <text>",
+"  The text replaces Kermit's built-in modem dialing command.  It must",
+"  include '%s' (percent s) as a place-holder for the telephone numbers",
+"  given in your DIAL commands.",
+" ",
+"SET MODEM ERROR-CORRECTION { ON, OFF }",
+"  Enables/disables the modem's error-correction feature, if any.",
+" ",
+"SET MODEM ESCAPE-CHARACTER number",
+"  Numeric ASCII value of modem's escape character, e.g. 43 for '+'.",
+"  For Hayes-compatible modems, Kermit uses three copies, e.g. \"+++\".",
+" ",
+"SET MODEM FLOW-CONTROL {AUTO, NONE, RTS/CTS, XON/XOFF}",
+"  Selects the type of local flow control to be used by the modem.",
+" ",
+"SET MODEM HANGUP-METHOD { MODEM-COMMAND, RS232-SIGNAL, DTR }",
+"  How hangup operations should be done.  MODEM-COMMAND means try to",
+"  escape back to the modem's command processor and give a modem-specific",
+"  hangup command.  RS232-SIGNAL means turn off the DTR signal.  DTR is a",
+"  synonym for RS232-SIGNAL.",
+" ",
+"SET MODEM KERMIT-SPOOF {ON, OFF}",
+"  If the selected modem type supports the Kermit protocol directly,",
+"  use this command to turn its Kermit protocol function on or off.",
+" ",
+"SET MODEM MAXIMUM-SPEED <number>",
+"  Specify the maximum interface speed for the modem.",
+" ",
+"SET MODEM NAME <text>",
+"  Descriptive name for a USER-DEFINED modem.",
+" ",
+"SET MODEM SPEAKER {ON, OFF}",
+"  Turns the modem's speaker on or off during dialing.",
+" ",
+"SET MODEM SPEED-MATCHING {ON, OFF}",
+"  ON means that C-Kermit changes its serial interface speed to agree with",
+"  the speed reported by the modem's CONNECT message, if any.  OFF means",
+"  Kermit should not change its interface speed.",
+" ",
+"SET MODEM VOLUME {LOW, MEDIUM, HIGH}",
+"  Selects the desired modem speaker volume for when the speaker is ON.",
+" ",
+"SET MODEM COMMAND commands are used to override built-in modem commands for",
+"each modem type, or to fill in commands for the USER-DEFINED modem type.",
+"Omitting the optional [ text ] restores the built-in modem-specific command,",
+"if any:",
+" ",
+"SET MODEM COMMAND AUTOANSWER {ON, OFF} [ text ]",
+"  Modem commands to turn autoanswer on and off.",
+" ",
+"SET MODEM COMMAND COMPRESSION {ON, OFF} [ text ]",
+"  Modem commands to turn data compression on and off.",
+" ",
+"SET MODEM COMMAND ERROR-CORRECTION {ON, OFF} [ text ]",
+"  Modem commands to turn error correction on and off.",
+" ",
+"SET MODEM COMMAND HANGUP [ text ]",
+"  Command that tells the modem to hang up the connection.",
+" ",
+"SET MODEM COMMAND IGNORE-DIALTONE [ text ]",
+"  Command that tells the modem not to wait for dialtone before dialing.",
+" ",
+"SET MODEM COMMAND INIT-STRING [ text ]",
+"  The 'text' is a replacement for C-Kermit's built-in initialization command",
+"  for the modem.",
+" ",
+"SET MODEM COMMAND PREDIAL-INIT [ text ]",
+"  A second INIT-STRING that is to be sent to the modem just prior to \
+dialing.",
+" ",
+"SET MODEM COMMAND HARDWARE-FLOW [ text ]",
+"  Modem command to enable hardware flow control (RTS/CTS) in the modem.",
+" ",
+"SET MODEM COMMAND SOFTWARE-FLOW [ text ]",
+"  Modem command to enable local software flow control (Xon/Xoff) in modem.",
+" ",
+"SET MODEM COMMAND SPEAKER { ON, OFF } [ text ]",
+"  Modem command to turn the modem's speaker on or off.",
+" ",
+"SET MODEM COMMAND NO-FLOW-CONTROL [ text ]",
+"  Modem command to disable local flow control in the modem.",
+" ",
+"SET MODEM COMMAND PULSE [ text ]",
+"  Modem command to select pulse dialing.",
+" ",
+"SET MODEM COMMAND TONE [ text ]",
+"  Modem command to select tone dialing.",
+" ",
+"SET MODEM COMMAND VOLUME { LOW, MEDIUM, HIGH } [ text ]",
+"  Modem command to set the modem's speaker volume.",
+""};
+
+static char *hmxydial[] = {
+"The SET DIAL command establishes or changes all parameters related to",
+"dialing the telephone.  Also see HELP DIAL and HELP SET MODEM.  Use SHOW",
+"DIAL to display all of the SET DIAL values.",
+" ",
+"SET DIAL COUNTRY-CODE <number>",
+"  Tells Kermit the telephonic country-code of the country you are dialing",
+"  from, so it can tell whether a portable-format phone number from your",
+"  dialing directory will result in a national or an international call.",
+"  Examples: 1 for USA, Canada, Puerto Rico, etc; 7 for Russia, 39 for Italy,",
+"  351 for Portugal, 47 for Norway, 44 for the UK, 972 for Israel, 81 for",
+"  Japan, ...",
+" ",
+"  If you have not already set your DIAL INTL-PREFIX and LD-PREFIX, then this",
+"  command sets default values for them: 011 and 1, respectively, for country",
+"  code 1; 00 and 0, respectively, for all other country codes.  If these are",
+"  not your true international and long-distance dialing prefixes, then you",
+"  should follow this command by DIAL INTL-PREFIX and LD-PREFIX to let Kermit",
+"  know what they really are.",
+" ",
+"SET DIAL AREA-CODE [ <number> ]",
+"  Tells Kermit the area or city code that you are dialing from, so it can",
+"  tell whether a portable-format phone number from the dialing directory is",
+"  local or long distance.  Be careful not to include your long-distance",
+"  dialing prefix as part of your area code; for example, the area code for",
+"  central London is 171, not 0171.",
+" ",
+"SET DIAL CONFIRMATION {ON, OFF}",
+"  Kermit does various transformations on a telephone number retrieved from",
+"  the dialing directory prior to dialing (use LOOKUP <name> to see them).",
+"  In case the result might be wrong, you can use SET DIAL CONFIRM ON to have",
+"  Kermit ask you if it is OK to dial the number, and if not, to let you type",
+"  in a replacement.",
+" ",
+"SET DIAL CONNECT { AUTO, ON, OFF }",
+"  Whether to CONNECT (enter terminal mode) automatically after successfully",
+"  dialing.  ON means to do this; OFF means not to.  AUTO (the default) means",
+"  do it if the DIAL command was given interactively, but don't do it if the",
+"  DIAL command was issued from a macro or command file.  If you specify ON",
+"  or AUTO, you may follow this by one of the keywords VERBOSE or QUIET, to",
+"  indicate whether the verbose 4-line 'Connecting...' message is to be",
+"  displayed if DIAL succeeds and Kermit goes into CONNECT mode.",
+" ",
+"SET DIAL CONVERT-DIRECTORY {ASK, ON, OFF}",
+"  The format of Kermit's dialing directory changed in version 5A(192).  This",
+"  command tells Kermit what to do when it encounters an old-style directory:",
+"  ASK you whether to convert it, or convert it automatically (ON), or leave",
+"  it alone (OFF).  Old-style directories can still be used without",
+"  conversion, but the parity and speed fields are ignored.",
+" ",
+"SET DIAL DIRECTORY [ filename [ filename [ filename [ ... ] ] ] ]",
+"  The name(s) of your dialing directory file(s).  If you do not supply any",
+"  filenames, the  dialing directory feature is disabled and all numbers are",
+"  dialed literally as given in the DIAL command.  If you supply more than",
+"  one directory, all of them are searched.",
+" ",
+"SET DIAL SORT {ON, OFF}",
+"  When multiple entries are obtained from your dialing directory, they are",
+"  sorted in \"cheapest-first\" order.  If this does not produce the desired",
+"  effect, SET DIAL SORT OFF to disable sorting, and the numbers will be",
+"  dialed in the order in which they were found.",
+" ",
+"SET DIAL DISPLAY {ON, OFF}",
+"  Whether to display dialing progress on the screen; default is OFF.",
+" ",
+"SET DIAL HANGUP {ON, OFF}",
+"  Whether to hang up the phone prior to dialing; default is ON.",
+" ",
+"SET DIAL IGNORE-DIALTONE {ON, OFF}",
+"  Whether to ignore dialtone when dialing; default is OFF.",
+" ",
+#ifndef NOSPL
+"SET DIAL MACRO [ name ]",
+"  Specify the name of a macro to execute on every phone number dialed, just",
+"  prior to dialing it, in order to perform any last-minute alterations.",
+" ",
+#endif /* NOSPL */
+"SET DIAL METHOD {AUTO, DEFAULT, TONE, PULSE}",
+"  Whether to use the modem's DEFAULT dialing method, or to force TONE or",
+"  PULSE dialing.  AUTO (the default) means to choose tone or pulse dialing",
+"  based on the country code.  (Also see SET DIAL TONE-COUNTRIES and SET DIAL",
+"  PULSE-COUNTRIES.)",
+" ",
+"SET DIAL PACING number",
+"  How many milliseconds to pause between sending each character to the modem",
+"  dialer.  The default is -1, meaning to use the number from the built-in",
+" modem database.",
+"  ",
+"SET DIAL PULSE-COUNTRIES [ cc [ cc [ ... ] ] ]",
+"  Sets the list of countries in which pulse dialing is required.  Each cc",
+"  is a country code.",
+" ",
+"SET DIAL TEST { ON, OFF }",
+"  OFF for normal dialing.  Set to ON to test dialing procedures without",
+"  actually dialing.",
+" ",
+"SET DIAL TONE-COUNTRIES [ cc [ cc [ ... ] ] ]",
+"  Sets the list of countries in which tone dialing is available.  Each cc",
+"  is a country code.",
+" ",
+"SET DIAL TIMEOUT number",
+"  How many seconds to wait for a dialed call to complete.  Use this command",
+"  to override the DIAL command's automatic timeout calculation.  A value",
+"  of 0 turns off this feature and returns to Kermit's automatic dial",
+"  timeout calculation.",
+" ",
+"SET DIAL RESTRICT { INTERNATIONAL, LOCAL, LONG-DISTANCE, NONE }",
+"  Prevents placing calls of the type indicated, or greater.  For example",
+"  SET DIAL RESTRICT LONG prevents placing of long-distance and international",
+"  calls.  If this command is not given, there are no restrictions.  Useful",
+"  when dialing a list of numbers fetched from a dialing directory.",
+" ",
+"SET DIAL RETRIES <number>",
+"  How many times to redial each number if the dialing result is busy or no",
+"  no answer, until the call is succesfully answered.  The default is 0",
+"  because automatic redialing is illegal in some countries.",
+" ",
+"SET DIAL INTERVAL <number>",
+"  How many seconds to pause between automatic redial attempts; default 10.",
+" ",
+"The following commands apply to all phone numbers, whether given literally",
+"or found in the dialing directory:",
+" ",
+"SET DIAL PREFIX [ text ]",
+"  Establish a prefix to be applied to all phone numbers that are dialed,",
+"  for example to disable call waiting.",
+" ",
+"SET DIAL SUFFIX [ text ]",
+"  Establish a suffix to be added after all phone numbers that are dialed.",
+" ",
+"The following commands apply only to portable-format numbers obtained from",
+"the dialing directory; i.e. numbers that start with a \"+\" sign and",
+"country code, followed by area code in parentheses, followed by the phone",
+"number.",
+" ",
+"SET DIAL LC-AREA-CODES [ <list> ]",
+"  Species a list of area codes to which dialing is local, i.e. does not",
+"  require the LD-PREFIX.  Up to 32 area codes may be listed, separated by",
+"  spaces.  Any area codes in this list will be included in the final dial",
+"  string so do not include your own area code if it should not be dialed.",
+" ",
+"SET DIAL LC-PREFIX [ <text> ]",
+"  Specifies a prefix to be applied to local calls made from portable dialing",
+"  directory entries.  Normally no prefix is used for local calls.",
+" ",
+"SET DIAL LC-SUFFIX [ <text> ]",
+"  Specifies a suffix to be applied to local calls made from portable dialing",
+"  directory entries.  Normally no suffix is used for local calls.",
+" ",
+"SET DIAL LD-PREFIX [ <text> ]",
+"  Your long-distance dialing prefix, to be used with portable dialing",
+"  directory entries that result in long-distance calls.",
+" ",
+"SET DIAL LD-SUFFIX [ <text> ]",
+"  Long-distance dialing suffix, if any, to be used with portable dialing",
+"  directory entries that result in long-distance calls.  This would normally",
+"  be used for appending a calling-card number to the phone number.",
+" ",
+"SET DIAL FORCE-LONG-DISTANCE { ON, OFF }",
+"  Whether to force long-distance dialing for calls that normally would be",
+"  local.  For use (e.g.) in France.",
+" ",
+"SET DIAL TOLL-FREE-AREA-CODE [ <number> [ <number> [ ... ] ] ]",
+"  Tells Kermit the toll-free area code(s) in your country.",
+" ",
+"SET DIAL TOLL-FREE-PREFIX [ <text> ]",
+"  You toll-free dialing prefix, in case it is different from your long-",
+"  distance dialing prefix.",
+" ",
+"SET DIAL INTL-PREFIX <text>",
+"  Your international dialing prefix, to be used with portable dialing",
+"  directory entries that result in international calls.",
+" ",
+"SET DIAL INTL-SUFFIX <text>",
+"  International dialing suffix, if any, to be used with portable dialing",
+"  directory entries that result in international calls.",
+" ",
+"SET DIAL PBX-OUTSIDE-PREFIX <text>",
+"  Use this to tell Kermit how to get an outside line when dialing from a",
+"  Private Branch Exchange (PBX).",
+" ",
+"SET DIAL PBX-EXCHANGE <text> [ <text> [ ... ] ]",
+"  If PBX-OUTSIDE-PREFIX is set, then you can use this command to tell Kermit",
+"  the leading digits of one or more local phone numbers that identify it as",
+"  being on your PBX, so it can make an internal call by deleting those digits"
+,
+"  from the phone number.",
+" ",
+"SET DIAL PBX-INTERNAL-PREFIX <text>",
+"  If PBX-EXCHANGE is set, and Kermit determines from it that a call is",
+"  internal, then this prefix, if any, is added to the number prior to",
+"  \
+dialing.  Use this if internal calls from your PBX require a special prefix.",
+"" };
+#endif /* NODIAL */
+
+static char *hmxyflo[] = { "Syntax: SET FLOW [ switch ] value",
+" ",
+#ifndef NOLOCAL
+"  Selects the type of flow control to use during file transfer, terminal",
+"  connection, and script execution.",
+#else
+"  Selects the type of flow control to use during file transfer.",
+#endif /* NOLOCAL */
+" ",
+"  Switches let you associate a particular kind of flow control with each",
+"  kind of connection: /REMOTE, /MODEM, /DIRECT-SERIAL, /TCPIP, etc; type",
+"  \"set flow ?\" for a list of available switches.  Then whenever you make",
+"  a connection, the associated flow-control is chosen automatically.",
+"  The flow-control values are NONE, KEEP, XON/XOFF, and possibly RTS/CTS",
+"  and some others; again, type \"set flow ?\" for a list.  KEEP tells Kermit",
+"  not to try to change the current flow-control method for the connection.",
+" ",
+"  If you omit the switch and simply supply a value, this value becomes the",
+"  current flow control type, overriding any default value that might have",
+"  been chosen in your most recent SET LINE, SET PORT, or SET HOST, or other",
+"  connection-establishment command.",
+" ",
+"  Type SHOW FLOW-CONTROL to see the current defaults for each connection type"
+,
+"  as well as the current connection type and flow-control setting.  SHOW",
+"  COMMUNICATIONS also shows the current flow-control setting.",
+""};
+
+static char *hmxyf[] = {
+"Syntax: SET FILE parameter value",
+" ",
+"Sets file-related parameters.  Use SHOW FILE to view them.  Also see SET",
+"(and SHOW) TRANSFER and PROTOCOL.",
+" ",
+#ifdef VMS
+"SET FILE TYPE { TEXT, BINARY, IMAGE, LABELED }",
+#else
+#ifdef STRATUS
+"SET FILE TYPE { TEXT, BINARY, LABELED }",
+#else
+#ifdef MAC
+"SET FILE TYPE { TEXT, BINARY, MACBINARY }",
+#else
+"SET FILE TYPE { TEXT, BINARY }",
+#endif /* STRATUS */
+#endif /* MAC */
+#endif /* VMS */
+"  How file contents are to be treated during file transfer in the absence",
+"  of any other indication.  TYPE can be TEXT for conversion of record format",
+"  and character set, which is usually needed when transferring text files",
+"  between unlike platforms (such as UNIX and Windows), or BINARY for no",
+"  conversion if TRANSFER MODE is MANUAL, which is not the default.  Use",
+"  BINARY with TRANSFER MODE MANUAL for executable programs or binary data or",
+"  whenever you wish to duplicate the original contents of the file, byte for"
+,
+"  byte.  In most modern Kermit programs, the file sender informs the receiver"
+,
+"  of the file type automatically.  However, when sending files from C-Kermit",
+"  to an ancient or non-Columbia Kermit implementation, you might need to set",
+"  the corresponding file type at the receiver as well.",
+" ",
+#ifdef VMS
+"  FILE TYPE settings of TEXT and BINARY have no effect when sending files,",
+"  since VMS C-Kermit determines each file's type automatically from its",
+"  record format: binary for fixed, text for others.  For incoming files,",
+"  these settings are effective only in the absence of a file-type indication",
+"  from the sender.",
+" ",
+"  You may include an optional record-format after the word BINARY.  This may",
+"  be FIXED (the default) or UNDEFINED.  UNDEFINED is used when you need to",
+"  receive binary files in binary mode and have them stored with UNDEFINED",
+"  record format, which is required by certain VMS applications.",
+" ",
+"  Two additional VMS file types are also supported: IMAGE and LABELED.",
+"  IMAGE means raw block i/o, no interference from RMS, applies to file",
+"  transmission only, and overrides the normal automatica file type",
+"  determination.   LABELED means to send or interpret RMS attributes",
+"  with the file.",
+" ",
+#else
+"  When TRANSFER MODE is AUTOMATIC (as it is by default), various automatic",
+"  methods (depending on the platform) are used to determine whether a file",
+"  is transferred in text or binary mode; these methods (which might include",
+"  content scan (see SET FILE SCAN below), filename pattern matching (SET FILE"
+,
+"  PATTERNS), client/server \"kindred-spirit\" recognition, or source file",
+"  record format) supersede the FILE TYPE setting but can, themselves, be",
+"  superseded by including a /BINARY or /TEXT switch in the SEND, GET, or",
+"  RECEIVE command.",
+" ",
+"  When TRANSFER MODE is MANUAL, the automatic methods are skipped for sending"
+,
+"  files; the FILE TYPE setting is used instead, which can be superseded on",
+"  a per-command basis with a /TEXT or /BINARY switch.",
+#endif /* VMS */
+" ",
+
+#ifndef NOXFER
+
+"SET FILE BYTESIZE { 7, 8 }",
+"  Normally 8.  If 7, Kermit truncates the 8th bit of all file bytes.",
+" ",
+#ifndef NOCSETS
+"SET FILE CHARACTER-SET name",
+"  Tells the encoding of the local file, ASCII by default.",
+"  The names ITALIAN, PORTUGUESE, NORWEGIAN, etc, refer to 7-bit ISO-646",
+"  national character sets.  LATIN1 is the 8-bit ISO 8859-1 Latin Alphabet 1",
+"  for Western European languages.",
+"  NEXT is the 8-bit character set of the NeXT workstation.",
+"  The CPnnn sets are for PCs.  MACINTOSH-LATIN is for the Macintosh.",
+#ifndef NOLATIN2
+"  LATIN2 is ISO 8859-2 for Eastern European languages that are written with",
+"  Roman letters.  Mazovia is a PC code page used in Poland.",
+#endif /* NOLATIN2 */
+#ifdef CYRILLIC
+"  KOI-CYRILLIC, CYRILLIC-ISO, and CP866 are 8-bit Cyrillic character sets.",
+"  SHORT-KOI is a 7-bit ASCII coding for Cyrillic.  BULGARIA-PC is a PC code",
+"  page used in Bulgaria",
+#endif /* CYRILLIC */
+#ifdef HEBREW
+"  HEBREW-ISO is ISO 8859-8 Latin/Hebrew.  CP862 is the Hebrew PC code page.",
+"  HEBREW-7 is like ASCII with the lowercase letters replaced by Hebrew.",
+#endif /* HEBREW */
+#ifdef GREEK
+"  GREEK-ISO is ISO 8859-7 Latin/Greek.  CP869 is the Greek PC code page.",
+"  ELOT-927 is like ASCII with the lowercase letters replaced by Greek.",
+#endif /* GREEK */
+#ifdef KANJI
+"  JAPANESE-EUC, JIS7-KANJI, DEC-KANJI, and SHIFT-JIS-KANJI are Japanese",
+"  Kanji character sets.",
+#endif /* KANJI */
+#ifdef UNICODE
+"  UCS-2 is the 2-byte form of the Universal Character Set.",
+"  UTF-8 is the serialized form of the Universal Character Set.",
+#endif /* UNICODE */
+"  Type SET FILE CHAR ? for a complete list of file character sets.",
+" ",
+"SET FILE DEFAULT 7BIT-CHARACTER-SET",
+"  When automatically switching among different kinds of files while sending",
+"  this tells the character set to be used for 7-bit text files.",
+" ",
+"SET FILE DEFAULT 8BIT-CHARACTER-SET",
+"  This tells the character set to be used for 8-bit text files when",
+"  switching automatically among different kinds of files.",
+" ",
+#endif /* NOCSETS */
+
+"SET FILE COLLISION option",
+"  Tells what to do when a file arrives that has the same name as",
+"  an existing file.  The options are:",
+"   BACKUP (default) - Rename the old file to a new, unique name and store",
+"     the incoming file under the name it was sent with.",
+"   OVERWRITE - Overwrite (replace) the existing file.",
+"   APPEND - Append the incoming file to the end of the existing file.",
+"   DISCARD - Refuse and/or discard the incoming file.",
+"   RENAME - Give the incoming file a unique name.",
+"   UPDATE - Accept the incoming file only if newer than the existing file.",
+" ",
+
+"SET FILE DESTINATION { DISK, PRINTER, SCREEN, NOWHERE }",
+"  DISK (default): Store incoming files on disk.",
+"  PRINTER:        Send incoming files to SET PRINTER device.",
+"  SCREEN:         Display incoming files on screen (local mode only).",
+"  NOWHERE:        Do not put incoming files anywhere (use for calibration).",
+" ",
+"SET FILE DISPLAY option",
+"  Selects the format of the file transfer display for local-mode file",
+"  transfer.  The choices are:",
+" ",
+"  BRIEF      A line per file, showing size, mode, status, and throughput.",
+"  SERIAL     One dot is printed for every K bytes transferred.",
+"  CRT        Numbers are continuously updated on a single screen line.",
+"             This format can be used on any video display terminal.",
+#ifdef CK_CURSES
+"  FULLSCREEN A fully formatted 24x80 screen showing lots of information.",
+"             This requires a terminal or terminal emulator.",
+#endif /* CK_CURSES */
+"  NONE       No file transfer display at all.",
+" ",
+
+"SET FILE DOWNLOAD-DIRECTORY [ <directory-name> ]",
+"  The directory into which all received files should be placed.  By default,",
+"  received files go into your current directory.",
+" ",
+#endif /* NOXFER */
+
+#ifdef CK_CTRLZ
+"SET FILE EOF { CTRL-Z, LENGTH }",
+"  End-Of-File detection method, normally LENGTH.  Applies only to text-mode",
+"  transfers.  When set to CTRL-Z, this makes the file sender treat the first",
+"  Ctrl-Z in the input file as the end of file (EOF), and it makes the file",
+"  receiver tack a Ctrl-Z onto the end of the output file if it does not",
+"  already end with Ctrl-Z.",
+" ",
+#endif /* CK_CTRLZ */
+
+"SET FILE END-OF-LINE { CR, CRLF, LF }",
+"  Use this command to specify nonstandard line terminators for text files.",
+" ",
+
+#ifndef NOXFER
+"SET FILE INCOMPLETE { AUTO, KEEP, DISCARD }",
+"  What to do with an incompletely received file: KEEP, DISCARD, or AUTO.",
+"  AUTO (the default) means DISCARD if transfer is in text mode, KEEP if it",
+"  is in binary mode.",
+" ",
+#ifdef VMS
+"SET FILE LABEL { ACL, BACKUP-DATE, NAME, OWNER, PATH } { ON, OFF }",
+"  Tells which items to include (ON) or exclude (OFF) in labeled file",
+"  transfers",
+" ",
+#else
+#ifdef OS2
+"SET FILE LABEL { ARCHIVE, READ-ONLY, HIDDEN, SYSTEM, EXTENDED } { ON, OFF }",
+"  Tells which items to include (ON) or exclude (OFF) in labeled file",
+"  transfers.",
+" ",
+#endif /* OS2 */
+#endif /* VMS */
+
+#ifdef UNIX
+#ifdef DYNAMIC
+"SET FILE LISTSIZE number",
+"  Changes the size of the internal wildcard expansion list.  Use SHOW FILE",
+"  to see the current size.  Use this command to increase the size if you get",
+"  a \"?Too many files\" error.  Also see SET FILE STRINGSPACE.",
+" ",
+#endif /* DYNAMIC */
+#endif /* UNIX */
+
+"SET FILE NAMES { CONVERTED, LITERAL }",
+"  File names are normally CONVERTED to \"common form\" during transmission",
+"  (e.g. lowercase to uppercase, extra periods changed to underscore, etc).",
+"  LITERAL means use filenames literally (useful between like systems).  Also",
+"  see SET SEND PATHNAMES and SET RECEIVE PATHNAMES.",
+" ",
+
+#ifdef UNIX
+"SET FILE OUTPUT { { BUFFERED, UNBUFFERED } [ size ], BLOCKING, NONBLOCKING }",
+"  Lets you control the disk output buffer for incoming files.  Buffered",
+"  blocking writes are normal.  Nonblocking writes might be faster on some",
+"  systems but might also be risky, depending on the underlying file service.",
+"  Unbuffered writes might be useful in critical applications to ensure that",
+"  cached disk writes are not lost in a crash, but will probably also be",
+"  slower.  The optional size parameter after BUFFERED or UNBUFFERED lets you",
+"  change the disk output buffer size; this might make a difference in",
+"  performance.",
+" ",
+#endif /* UNIX */
+
+#ifdef PATTERNS
+"SET FILE PATTERNS { ON, OFF, AUTO }",
+"  ON means to use filename pattern lists to determine whether to send a file",
+"  in text or binary mode.  OFF means to send all files in the prevailing",
+"  mode.  AUTO (the default) is like ON if the other Kermit accepts Attribute",
+"  packets and like OFF otherwise.  FILE PATTERNS are used only if FILE SCAN",
+"  is OFF (see SET FILE SCAN).",
+" ",
+"SET FILE BINARY-PATTERNS [ <pattern> [ <pattern> ... ] ]",
+"  Zero or more filename patterns which, if matched, cause a file to be sent",
+"  in binary mode when FILE PATTERNS are ON.  HELP WILDCARDS for a description"
+,
+"  of pattern syntax.  SHOW PATTERNS to see the current file pattern lists.",
+" ",
+"SET FILE TEXT-PATTERNS [ <pattern> [ <pattern> ... ] ]",
+"  Zero or more filename patterns which, if matched, cause a file to be sent",
+"  in text mode when FILE PATTERNS is ON; if a file does not match a text or",
+"  binary pattern, the prevailing SET FILE TYPE is used.",
+" ",
+#endif /* PATTERNS */
+
+#ifdef VMS
+"SET FILE RECORD-LENGTH number",
+"  Sets the record length for received files of type BINARY.  Use this to",
+"  receive VMS BACKUP savesets or other fixed-format files that do not use",
+"  the default record length of 512.",
+" ",
+#endif /* VMS */
+
+"SET FILE SCAN { ON [ size ], OFF }",
+"  If TRANSFER MODE is AUTOMATIC and FILE SCAN is ON (as it is by default)",
+"  Kermit peeks at the file's contents to see if it's text or binary.  Use",
+"  SET FILE SCAN OFF to disable file peeking, while still keeping TRANSFER",
+"  MODE automatic to allow name patterns and other methods.  The optional",
+"  size is the number of file bytes to scan, 49152 by default.  -1 means to",
+"  scan the whole file.  Also see SET FILE PATTERNS.",
+" ",
+
+#ifdef UNIX
+#ifdef DYNAMIC
+"SET FILE STRINGSPACE number",
+"  Changes the size (in bytes) of the internal buffer that holds lists of",
+"  filenames such as wildcard expansion lists.  Use SHOW FILE to see the",
+"  current size.  Use this command to increase the size if you get a",
+"  \"?String space exhausted\" error.  Also see SET FILE LISTSIZE.",
+" ",
+#endif /* DYNAMIC */
+#endif /* UNIX */
+
+#ifdef UNICODE
+"SET FILE UCS BOM { ON, OFF }",
+"  Whether to write a Byte Order Mark when creating a UCS-2 file.",
+" ",
+"SET FILE UCS BYTE-ORDER { BIG-ENDIAN, LITTLE-ENDIAN }",
+"  Byte order to use when creating UCS-2 files, and to use when reading UCS-2",
+"  files that do not start with a Byte Order Mark.",
+" ",
+#endif /* UNICODE */
+
+"SET FILE WARNING { ON, OFF }",
+"  SET FILE WARNING is superseded by the newer command, SET FILE",
+"  COLLISION.  SET FILE WARNING ON is equivalent to SET FILE COLLISION RENAME",
+"  and SET FILE WARNING OFF is equivalent to SET FILE COLLISION OVERWRITE.",
+#endif /* NOXFER */
+"" };
+
+static char *hmxyhsh[] = {
+"Syntax: SET HANDSHAKE { NONE, XON, LF, BELL, ESC, CODE number }",
+"  Character to use for half duplex line turnaround handshake during file",
+"  transfer.  C-Kermit waits for this character from the other computer",
+"  before sending its next packet.  Default is NONE; you can give one of the",
+"  other names like BELL or ESC, or use SET HANDSHAKE CODE to specify the",
+"  numeric code value of the handshake character.  Type SET HANDSH ? for a",
+"  complete list of possibilities.",
+"" };
+
+#ifndef NOSERVER
+static char *hsetsrv[] = {
+"SET SERVER CD-MESSAGE {ON,OFF}",
+"  Tells whether the server, after successfully executing a REMOTE CD",
+"  command, should send the contents of the new directory's READ.ME",
+"  (or similar) file to your screen.",
+" ",
+"SET SERVER CD-MESSAGE FILE name",
+"  Tells the name of the file to be displayed as a CD-MESSAGE, such as",
+"  READ.ME (SHOW SERVER tells the current CD-MESSAGE FILE name).",
+"  To specify more than one filename to look for, use {{name1}{name2}..}.",
+"  Synonym: SET CD MESSAGE FILE <list>.",
+" ",
+"SET SERVER DISPLAY {ON,OFF}",
+"  Tells whether local-mode C-Kermit during server operation should put a",
+"  file transfer display on the screen.  Default is OFF.",
+" ",
+"SET SERVER GET-PATH [ directory [ directory [ ... ] ] ]",
+"  Tells the C-Kermit server where to look for files whose names it receives",
+"  from client GET commands when the names are not fully specified pathnames.",
+"  Default is no GET-PATH, so C-Kermit looks only in its current directory.",
+" ",
+"SET SERVER IDLE-TIMEOUT seconds",
+"  Idle time limit while in server mode, 0 for no limit.",
+#ifndef OS2
+"  NOTE: SERVER IDLE-TIMEOUT and SERVER TIMEOUT are mutually exclusive.",
+#endif /* OS2 */
+" ",
+"SET SERVER KEEPALIVE {ON,OFF}",
+"  Tells whether C-Kermit should send \"keepalive\" packets while executing",
+"  REMOTE HOST commands, which is useful in case the command takes a long",
+"  time to produce any output and therefore might cause the operation to time",
+"  out.  ON by default; turn it OFF if it causes trouble with the client or",
+"  slows down the server too much.",
+" ",
+"SET SERVER LOGIN [ username [ password [ account ] ] ]",
+"  Sets up a username and optional password which must be supplied before",
+"  the server will respond to any commands other than REMOTE LOGIN.  The",
+"  account is ignored.  If you enter SET SERVER LOGIN by itself, then login",
+"  is no longer required.  Only one SET SERVER LOGIN command can be in effect",
+"  at a time; C-Kermit does not support multiple user/password pairs.",
+" ",
+"SET SERVER TIMEOUT n",
+"  Server command wait timeout interval, how often the C-Kermit server issues",
+"  a NAK while waiting for a command packet.  Specify 0 for no NAKs at all.",
+"  Default is 0.",
+""
+};
+#endif /* NOSERVER */
+
+static char *hmhrmt[] = {
+#ifdef NEWFTP
+"The REMOTE command sends file management instructions or other commands",
+"to a Kermit or FTP server.  If you have a single connection, the command is",
+"directed to the server you are connected to; if you have multiple connections"
+,
+"the command is directed according to your GET-PUT-REMOTE setting.",
+#else
+"The REMOTE command sends file management instructions or other commands",
+"to a Kermit server.  There should already be a Kermit running in server",
+"mode on the other end of the connection.",
+#endif /* NEWFTP */
+"Type REMOTE ? to see a list of available remote commands.  Type HELP REMOTE",
+"xxx to get further information about a particular remote command xxx.",
+" ",
+"All REMOTE commands except LOGIN and LOGOUT have R-command shortcuts;",
+"for example, RDIR for REMOTE DIR, RCD for REMOTE CD, etc.",
+" ",
+#ifdef NEWFTP
+#ifdef LOCUS
+"Also see: HELP SET LOCUS, HELP FTP, HELP SET GET-PUT-REMOTE.",
+#else
+"Also see: HELP FTP, HELP SET GET-PUT-REMOTE.",
+#endif /* LOCUS */
+#else
+#ifdef LOCUS
+"Also see: HELP SET LOCUS.",
+#endif /* LOCUS */
+#endif /* NEWFTP */
+"" };
+
+#ifndef NOSPL
+static char *ifhlp[] = { "Syntax: IF [NOT] condition commandlist",
+" ",
+"If the condition is (is not) true, do the commandlist.  The commandlist",
+"can be a single command, or a list of commands separated by commas and",
+"enclosed in braces.  The condition can be a single condition or a group of",
+"conditions separated by AND (&&) or OR (||) and enclosed in parentheses.",
+"If parentheses are used they must be surrounded by spaces.  Examples:",
+" ",
+"  IF EXIST oofa.txt <command>",
+"  IF ( EXIST oofa.txt || = \\v(nday) 3 ) <command>",
+"  IF ( EXIST oofa.txt || = \\v(nday) 3 ) { <command>, <command>, ... }",
+" ",
+"The conditions are:",
+" ",
+"  SUCCESS     - The previous command succeeded",
+"  OK          - Synonym for SUCCESS",
+"  FAILURE     - The previous command failed",
+"  ERROR       - Synonym for FAILURE",
+"  FLAG        - Succeeds if SET FLAG ON, fails if SET FLAG OFF",
+"  BACKGROUND  - C-Kermit is running in the background",
+#ifdef CK_IFRO
+"  FOREGROUND  - C-Kermit is running in the foreground",
+"  REMOTE-ONLY - C-Kermit was started with the -R command-line option",
+#else
+"  FOREGROUND  - C-Kermit is running in the foreground",
+#endif /* CK_IFRO */
+"  KERBANG     - A Kerbang script is running",
+"  ALARM       - SET ALARM time has passed",
+"  ASKTIMEOUT  - The most recent ASK, ASKQ, GETC, or GETOK timed out",
+"  EMULATION   - Succeeds if executed while in CONNECT mode",
+#ifdef OS2
+"  TAPI        - Current connection is via a Microsoft TAPI device",
+#endif /* OS2 */
+" ",
+"  MS-KERMIT   - Program is MS-DOS Kermit",
+"  C-KERMIT    - Program is C-Kermit",
+"  K-95        - Program is Kermit 95",
+"  GUI         - Program runs in a GUI window",
+" ",
+"  AVAILABLE CRYPTO                  - Encryption is available",
+"  AVAILABLE KERBEROS4               - Kerberos 4 authentication is available",
+"  AVAILABLE KERBEROS5               - Kerberos 5 authentication is available",
+"  AVAILABLE NTLM                    - NTLM authentication is available",
+"  AVAILABLE SRP                     - SRP authentication is available",
+"  AVAILABLE SSL                     - SSL/TLS authentication is available",
+"  MATCH string pattern              - Succeeds if string matches pattern",
+#ifdef CKFLOAT
+"  FLOAT number                      - Succeeds if floating-point number",
+#endif /* CKFLOAT */
+"  COMMAND word                      - Succeeds if word is built-in command",
+"  DEFINED variablename or macroname - The named variable or macro is defined",
+"  DECLARED arrayname                - The named array is declared",
+"  NUMERIC variable or constant      - The variable or constant is numeric",
+"  EXIST filename                    - The named file exists",
+"  ABSOLUTE filename                 - The filename is absolute, not relative",
+#ifdef CK_TMPDIR
+"  DIRECTORY string                  - The string is the name of a directory",
+#endif /* CK_TMPDIR */
+"  READABLE filename                 - Succeeds if the file is readable",
+"  WRITEABLE filename                - Succeeds if the file is writeable",
+#ifdef ZFCDAT
+"  NEWER file1 file2                 - The 1st file is newer than the 2nd one",
+#endif /* ZFCDAT */
+"  OPEN { READ-FILE,SESSION-LOG,...} - The given file or log is open",
+#ifndef NOLOCAL
+"  OPEN CONNECTION                   - A connection is open",
+#endif /* NOLOCAL */
+"  KBHIT                             - A key has been pressed",
+" ",
+"  VERSION - equivalent to \"if >= \\v(version) ...\"",
+"  COUNT   - subtract one from COUNT, execute the command if the result is",
+"            greater than zero (see SET COUNT)",
+" ",
+"  EQUAL s1 s2 - s1 and s2 (character strings or variables) are equal",
+"  LLT s1 s2   - s1 is lexically (alphabetically) less than s2",
+"  LGT s1 s1   - s1 is lexically (alphabetically) greater than s2",
+" ",
+"  =  n1 n2 - n1 and n2 (numbers or variables containing numbers) are equal",
+"  <  n1 n2 - n1 is arithmetically less than n2",
+"  <= n1 n2 - n1 is arithmetically less than or equal to n2",
+"  >  n1 n2 - n1 is arithmetically greater than n2",
+"  >= n1 n2 - n1 is arithmetically greater than or equal to n2",
+" ",
+"  (number by itself) - fails if the number is 0, succeeds otherwise",
+" ",
+"  TRUE     - always succeeds",
+"  FALSE    - always fails",
+" ",
+"The IF command may be followed on the next line by an ELSE command. Example:",
+" ",
+"  IF < \\%x 10 ECHO It's less",
+"  ELSE echo It's not less",
+" ",
+"It can also include an ELSE part on the same line if braces are used:",
+" ",
+"  IF < \\%x 10 { ECHO It's less } ELSE { ECHO It's not less }",
+" ",
+"Also see HELP WILDCARD (for IF MATCH pattern syntax).",
+"" };
+
+static char *hmxxeval[] = { "Syntax: EVALUATE variable expression",
+"  Evaluates the expression and assigns its value to the given variable.",
+"  The expression can contain numbers and/or numeric-valued variables or",
+"  functions, combined with mathematical operators and parentheses in",
+"  traditional notation.  Operators include +-/*(), etc.  Example:",
+"  EVALUATE \\%n (1+1) * (\\%a / 3).",
+" ",
+"  NOTE: Prior to C-Kermit 7.0, the syntax was \"EVALUATE expression\"",
+"  (no variable), and the result was printed.  Use SET EVAL { OLD, NEW }",
+"  to choose the old or new behavior, which is NEW by default.",
+" ",
+"Alse see: HELP FUNCTION EVAL.",
+"" };
+#endif /* NOSPL */
+
+static char *hmxxexit[] = {
+"Syntax: EXIT (or QUIT) [ number [ text ] ]",
+"  Exits from the Kermit program, closing all open files and devices.",
+"  If a number is given it becomes Kermit's exit status code.  If text is",
+"  included, it is printed.  Also see SET EXIT.",
+"" };
+
+#ifndef NOSPL
+static char *ifxhlp[] = { "\
+Syntax: XIF condition { commandlist } [ ELSE { commandlist } ]",
+"  Obsolete.  Same as IF (see HELP IF).",
+"" };
+
+static char *forhlp[] = { "\
+Syntax: FOR variablename initial-value final-value increment { commandlist }",
+"  FOR loop.  Execute the comma-separated commands in the commandlist the",
+"  number of times given by the initial value, final value and increment.",
+"  Example:  FOR \\%i 10 1 -1 { pause 1, echo \\%i }", "" };
+
+static char *whihlp[] = { "\
+Syntax: WHILE condition { commandlist }",
+"  WHILE loop.  Execute the comma-separated commands in the bracketed",
+"  commandlist while the condition is true.  Conditions are the same as for",
+"  IF commands.",
+"" };
+
+static char *swihlp[] = {
+"Syntax: SWITCH <variable> { case-list }",
+"  Selects from a group of commands based on the value of a variable.",
+"  The case-list is a series of lines like these:",
+" ",
+"    :x, command, command, ..., break",
+" ",
+"  where \"x\" is a possible value for the variable.  At the end of the",
+"  case-list, you can put a \"default\" label to catch when the variable does",
+"  not match any of the labels:",
+" ",
+"    :default, command, command, ...",
+" ",
+"The case label \"x\" can be a character, a string, a variable, a function",
+"invocation, a pattern, or any combination of these.  See HELP WILDCARDS",
+"for information about patterns.",
+""};
+
+static char *openhlp[] = {
+"Syntax:  OPEN mode filename",
+"  For use with READ and WRITE commands.  Open the local file in the",
+"  specified mode: READ, WRITE, or APPEND.  !READ and !WRITE mean to read",
+"  from or write to a system command rather than a file.  Examples:",
+" ",
+"    OPEN READ oofa.txt",
+"    OPEN !READ sort foo.bar",
+"" };
+
+static char *hxxask[] = {
+"Syntax:  ASK [ switches ] variablename [ prompt ]",
+"Example: ASK \\%n { What is your name\\? }",
+"  Issues the prompt and defines the variable to be whatever is typed in",
+"  response, up to the terminating carriage return.  Use braces to preserve",
+"  leading and/or trailing spaces in the prompt.",
+" ",
+"Syntax:  ASKQ [ switches ] variablename [ prompt ]",
+"Example: ASKQ \\%p { Password:}",
+"  Like ASK except the response does not echo on the screen.",
+" ",
+"Switches:",
+" /DEFAULT:text",
+"  Text to supply if the user enters a blank response or the /TIMEOUT",
+"  limit expired with no response.",
+" ",
+#ifdef OS2
+" /POPUP",
+"  The prompt and response dialog takes place in a text-mode popup.",
+"  K95 only; in C-Kermit this switch is ignored.",
+" ",
+#ifdef KUI
+" /GUI",
+"  The prompt and response dialog takes place in a GUI popup.",
+"  K95 GUI version only; in C-Kermit and the K95 console version,", 
+"  this switch is ignored.",
+" ",
+#endif /* KUI */
+#endif /* OS2 */
+" /TIMEOUT:number",
+"  If the response is not entered within the given number of seconds, the",
+"  command fails.  This is equivalent to setting ASK-TIMER to a positive",
+"  number, except it applies only to this command.  Also see SET ASK-TIMER.",
+"  NOTE: If a /DEFAULT: value was also given, it is supplied automatically",
+"  upon timeout and the command does NOT fail.",
+
+" ",
+" /QUIET",
+"  Suppresses \"?Timed out\" message when /TIMEOUT is given and user doesn't",
+"  respond within the time limit.",
+""};
+static char *hxxgetc[] = {
+"Syntax:  GETC variablename [ prompt ]",
+"Example: GETC \\%c { Type any character to continue...}",
+"  Issues the prompt and sets the variable to the first character you type.",
+"  Use braces to preserve leading and/or trailing spaces in the prompt.",
+" ",
+"Also see SET ASK-TIMER.",
+""};
+
+static char *hmxytimer[] = {
+"Syntax: SET ASK-TIMER number",
+"  For use with ASK, ASKQ, GETOK, and GETC.  If ASK-TIMER is set to a number",
+"  greater than 0, these commands will time out after the given number of",
+"  seconds with no response.  This command is \"sticky\", so to revert to",
+" \
+untimed ASKs after a timed one, use SET ASK-TIMER 0.  Also see IF ASKTIMEOUT.",
+""};
+
+static char *hxxdot[] = {
+"Syntax: .<variable-name> <assignment-operator> <value>",
+"  Assigns the value to the variable in the manner indicated by the",
+"  assignment operator:",
+"  =   Copies without evaluation (like DEFINE).",
+"  :=  Copies with evaluation (like ASSIGN).",
+"  ::= Copies with arithmetic evaluation (like EVALUATE).",
+""};
+
+static char *hxxdef[] = {
+"Syntax: DEFINE name [ definition ]",
+"  Defines a macro or variable.  Its value is the definition, taken",
+"  literally.  No expansion or evaluation of the definition is done.  Thus",
+"  if the definition includes any variable or function references, their",
+"  names are included, rather than their values (compare with ASSIGN).  If",
+"  the definition is omitted, then the named variable or macro is undefined.",
+" ",
+"A typical macro definition looks like this:",
+" ",
+"  DEFINE name command, command, command, ...",
+" ",
+"for example:",
+" ",
+"  DEFINE vax set parity even, set duplex full, set flow xon/xoff",
+" ",
+"which defines a Kermit command macro called 'vax'.  The definition is a",
+"comma-separated list of Kermit commands.  Use the DO command to execute",
+"the macro, or just type its name, followed optionally by arguments.",
+" ",
+"The definition of a variable can be anything at all, for example:",
+" ",
+"  DEFINE \\%a Monday",
+"  DEFINE \\%b 3",
+" ",
+"These variables can be used almost anywhere, for example:",
+" ",
+"  ECHO Today is \\%a",
+"  SET BLOCK-CHECK \\%b",
+"" };
+
+static char *hxxass[] = {
+"Syntax:  ASSIGN variablename string.",
+"Example: ASSIGN \\%a My name is \\%b.",
+"  Assigns the current value of the string to the variable (or macro).",
+"  The definition string is fully evaluated before it is assigned, so that",
+"  the values of any variables that are contained are used, rather than their",
+"  names.  Compare with DEFINE.  To illustrate the difference, try this:",
+" ",
+"    DEFINE \\%a hello",
+"    DEFINE \\%x \\%a",
+"    ASSIGN \\%y \\%a",
+"    DEFINE \\%a goodbye",
+"    ECHO \\%x \\%y",
+" ",
+"  This prints 'goodbye hello'.", "" };
+
+static char *hxxdec[] = {
+"Syntax: DECREMENT variablename [ number ]",
+"  Decrement (subtract one from) the value of a variable if the current value",
+"  is numeric.  If the number argument is given, subtract that number",
+"  instead.",
+" ",
+"Examples: DECR \\%a, DECR \\%a 7, DECR \\%a \\%n", "" };
+
+static char *hxxinc[] = {
+"Syntax: INCREMENT variablename [ number ]",
+"  Increment (add one to) the value of a variable if the current value is",
+"  numeric.  If the number argument is given, add that number instead.",
+" ",
+"Examples: INCR \\%a, INCR \\%a 7, INCR \\%a \\%n", "" };
+#endif /* NOSPL */
+
+#ifdef ANYX25
+#ifndef IBMX25
+static char *hxxpad[] = {
+"Syntax: PAD command",
+"X.25 PAD commands:",
+" ",
+"    PAD CLEAR     - Clear the virtual call",
+"    PAD STATUS    - Return the status of virtual call",
+"    PAD RESET     - Send a reset packet",
+"    PAD INTERRUPT - Send an interrupt packet",
+""};
+#endif /* IBMX25 */
+
+static char *hxyx25[] = {
+"Syntax: SET X.25 option { ON [ data ], OFF }",
+" ",
+"X.25 call options:",
+"  CLOSED-USER-GROUP { ON index, OFF }",
+"    Enable or disable closed user group call, where index is the group",
+"    index, 0 to 99.",
+"  REVERSE-CHARGE { ON, OFF }",
+"    Tell whether you want to reverse the charges for the call.",
+"  CALL-USER-DATA { ON string, OFF }",
+"    Specify call user-data for the X.25 call.",
+""};
+#endif /* ANYX25 */
+
+static char *hxyprtr[] = {
+#ifdef PRINTSWI
+"Syntax: SET PRINTER [ switches ] [ name ]",
+" ",
+"  Specifies the printer to be used for transparent-print, autoprint, and",
+"  screen-dump material during terminal emulation, as well as for the PRINT",
+"  command, plus various options governing print behavior.",
+" ",
+"Switches for specifying the printer by type:",
+" ",
+"/NONE",
+"  Include this switch to specify that all printer actions should simply be",
+"  skipped.  Use this, for example, if you have no printer.",
+" ",
+"/DOS-DEVICE[:name]",
+"  Include this to declare a DOS printer and to specify its name, such as",
+"  PRN, LPT1, etc.",
+" ",
+#ifdef NT
+"/WINDOWS-QUEUE[:[queue-name]]",
+"  Include this to declare a Windows printer and specify its queue name.",
+"  Type question mark (?) after the colon (:) to see a list of known queue",
+"  names.  If the colon is absent, the switch indicates the currently",
+"  selected printer is a Windows Print Queue.  If the colon is provided",
+"  and the name is absent, the Windows Print Queue chosen as the Default",
+"  Printer is selected.",
+" ",
+#endif /* NT */
+"/FILE[:name]",
+"  Specifies that all printer material is to be appended to the named file,",
+"  rather than being sent to a printer.  If the file does not exist, it is",
+"  created the first time any material is to be printed.",
+" ",
+"/PIPE[:name]",
+"  Specifies that all printer material is to be sent as standard input to",
+"  the program or command whose name is given.  Example:",
+" ",
+"    SET PRINTER /PIPE:{textps > lpt1}",
+" ",
+"If you give a printer name without specifying any of these switches, then it",
+"is assumed to be a DOS printer device or filename unless the name given",
+"(after removing enclosing braces, if any) starts with \"|\", \
+in which case it",
+"is a pipe.  Examples:",
+" ",
+"  SET PRINTER LPT1               <-- DOS device",
+"  SET PRINTER {| textps > lpt1}  <-- Pipe",
+" ",
+"The next group of switches tells whether the printer is one-way or",
+"bidirectional (two-way):",
+" ",
+"/OUTPUT-ONLY",
+"  Include this to declare the printer capable only of receiving material to",
+"  be printed, but not sending anything back.  This is the normal kind of",
+"  printer, Kermit's default kind, and the opposite of /BIDIRECTIONAL.",
+" ",
+"/BIDIRECTIONAL",
+"  Include this to declare the printer bidirectional.  This is the opposite ",
+"  of /OUTPUT-ONLY.  You can also use this option with serial printers, even",
+"  if they aren't bidirectional, in case you need to specify speed, flow",
+"  control, or parity.",
+" ",
+"The next group applies only to bidirectional and/or serial printers:",
+" ",
+"/FLOW-CONTROL:{NONE,XON/XOFF,RTS/CTS,KEEP}",
+"  Flow control to use with a serial bidirectional printer, default KEEP;",
+#ifdef NT
+"  i.e. use whatever the Windows driver for the port normally uses.",
+#else
+"  i.e. use whatever the OS/2 driver for the port normally uses.",
+#endif /* NT */
+" ",
+"/PARITY:{NONE,EVEN,ODD,SPACE,MARK}",
+"  Parity to use with a serial printer, default NONE; i.e. use 8 data bits",
+"  and no parity.  If you omit the colon and the keyword, NONE is selected.",
+" ",
+"/SPEED:number",
+"  Interface speed, in bits per second, to use with a serial printer, such as",
+"  2400, 9600, 19200, etc.  Type SET PRINTER /SPEED:? for a list of possible",
+"  speeds.",
+" ",
+"The next group deals with print jobs -- how to identify them, how to start",
+"them, how to terminate them:",
+" ",
+"/TIMEOUT[:number]",
+"  Used with host-directed transparent or auto printing, this is the number",
+"  of seconds to wait after the host closes the printer before terminating",
+"  the print job if the printer is not opened again during the specified",
+"  amount of time.",
+" ",
+"/JOB-HEADER-FILE[:filename]",
+"  The name of a file to be sent to the printer at the beginning of each",
+"  print job, as a burst page, or to configure the printer.  Normally no file",
+"  is is sent.",
+" ",
+"/END-OF-JOB-STRING[:string]",
+"  String of characters to be sent to the printer at the end of the print",
+"  job, usually used to force the last or only page out of the printer.  When",
+"  such a string is needed, it usually consists of a single formfeed: \"set",
+"  printer /end-of-job:{\\12}\".  No end-of-job string is sent unless you",
+"  specify one with this option.  If the string contains any spaces or",
+"  control characters (even in backslash notation, as above), enclose it in",
+"  braces.",
+" ",
+"The next group is for use with printers that print only PostScript:",
+" ",
+"/POSTSCRIPT or /PS",
+"  Indicates that K95 should convert all text to PostScript before sending",
+"  it to the printer.  The fixed-pitch Courier-11 font is used.",
+" ",
+"/WIDTH:number",
+"  Specifies the width of the page in characters.  If this switch is not",
+"  given, 80 is used.",
+" ",
+"/HEIGHT:number",
+"  Specifies the height of the page in lines.  If this switch is not given",
+"  66 is used.",
+" ",
+"/NOPOSTSCRIPT or /NOPS",
+"  Indicates that K95 should not convert all text to PostScript before",
+"  sending it to the printer.",
+" ",
+"The final switch is for use with AutoPrint mode and Screen Dumps",
+" ",
+"/CHARACTER-SET:<character-set>",
+"  Specifies the character set used by the printer which may be different",
+"  from both the character set used by the host and by the local computer.",
+"  The default value is CP437.",
+" ",
+"SHOW PRINTER displays your current printer settings.",
+#else
+#ifdef UNIX
+"Syntax: SET PRINTER [ { |command, filename } ]",
+"  Specifies the command (such as \"|lpr\") or filename to be used by the",
+"  PRINT command.  If a filename is given, each PRINT command appends to the",
+"  given file.  If the SET PRINTER argument contains spaces, it must be",
+"  enclosed in braces, e.g. \"set printer {| lpr -Plaser}\". If the argument",
+"  is omitted the default value is restored.  SHOW PRINTER lists the current",
+"  printer.  See HELP PRINT for further info.",
+#else
+"Sorry, SET PRINTER not available yet.",
+#endif /* UNIX */
+#endif /* PRINTSWI */
+""};
+
+#ifdef OS2
+#ifdef BPRINT
+static char *hxybprtr[] = {
+"Syntax: SET BPRINTER [ portname speed [ parity [ flow-control ] ] ]",
+"  (Obsolete, replaced by SET PRINTER /BIDIRECTIONAL.)",
+""};
+#endif /* BPRINT */
+#endif /* OS2 */
+
+static char *hxyexit[] = {
+"Syntax: SET EXIT HANGUP { ON, OFF }",
+"  When ON (which is the default), C-Kermit executes an implicit HANGUP and",
+"  CLOSE command on the communications device or connection when it exits.",
+"  When OFF, Kermit skips this sequence.",
+" ",
+"Syntax: SET EXIT ON-DISCONNECT { ON, OFF }",
+"  When ON, C-Kermit EXITs automatically when a network connection",
+"  is terminated either by the host or by issuing a HANGUP command.",
+" ",
+"Syntax: SET EXIT STATUS number",
+#ifdef NOSPL
+"  Set C-Kermit's program return code to the given number.",
+#else
+"  Set C-Kermit's program return code to the given number, which can be a",
+"  constant, variable, function result, or arithmetic expression.",
+#endif /* NOSPL */
+" ",
+"Syntax: SET EXIT WARNING { ON, OFF, ALWAYS }",
+"  When EXIT WARNING is ON, issue a warning message and ask for confirmation",
+"  before EXITing if a connection to another computer might still be open.",
+"  When EXIT WARNING is ALWAYS, confirmation is always requested.  When OFF",
+"  it is never requested.  The default is ON.",
+"" };
+
+#ifndef NOSPL
+static char *hxxpau[] = {
+"Syntax:  PAUSE [ { number-of-seconds, hh:mm:ss } ]",
+"Example: PAUSE 3  or  PAUSE 14:52:30",
+"  Do nothing for the specified number of seconds or until the given time of",
+"  day in 24-hour hh:mm:ss notation.  If the time of day is earlier than the",
+"  current time, it is assumed to be tomorrow.  If no argument given, one",
+"  second is used.  The pause can be interrupted by typing any character on",
+"  the keyboard unless SLEEP CANCELLATION is OFF.  If interrupted, PAUSE",
+"  fails, otherwise it succeeds.  Synonym: SLEEP.",
+"" };
+
+static char *hxxmsl[] = {
+"Syntax:  MSLEEP [ number ]",
+"Example: MSLEEP 500",
+"  Do nothing for the specified number of milliseconds; if no number given,",
+"  100 milliseconds.","" };
+#endif /* NOSPL */
+
+#ifndef NOPUSH
+extern int nopush;
+static char *hxxshe[] = {
+"Syntax: !, @, RUN, PUSH, or SPAWN, optionally followed by a command.",
+"  Gives the command to the local operating system's command processor, and",
+"  displays the results on the screen.  If the command is omitted, enters the",
+"  system's command line interpreter or shell; exit from it (the command for",
+"  this is usually EXIT or QUIT or LOGOUT) to return to Kermit.",
+""
+};
+#endif /* NOPUSH */
+
+#ifndef NOXMIT
+static char *hxxxmit[] = {
+"Syntax: TRANSMIT [ switches ] filename",
+"  Sends the contents of a file, without any error checking or correction,",
+"  to the computer on the other end of your SET LINE or SET HOST connection",
+"  (or if C-Kermit is in remote mode, displays it on the screen).  The",
+"  filename is the name of a single file (no wildcards) to be sent or, if",
+"  the /PIPE switch is included, the name of a command whose output is to be",
+"  sent.",
+" ",
+"  The file is sent according to your current FILE TYPE setting (BINARY or",
+"  TEXT), which you can override with a /BINARY or /TEXT switch without",
+"  changing the global setting.  In text mode, it is sent a line at a time,",
+"  with carriage return at the end of each line (as if you were typing it at",
+"  your keyboard), and C-Kermit waits for a linefeed to echo before sending",
+"  the next line; use /NOWAIT to eliminate the feedback requirement.  In",
+"  binary mode, it is sent a character at a time, with no feedback required.",
+" ",
+"  Normally the transmitted material is echoed to your screen.  Use SET",
+"  TRANSMIT ECHO OFF or the /NOECHO switch to suppress echoing.  Note that",
+"  TRANSMIT /NOECHO /NOWAIT /BINARY is a special case, that more or less",
+"  blasts the file out at full speed.",
+" ",
+#ifndef NOCSETS
+"  Character sets are translated according to your current FILE and TERMINAL",
+"  CHARACTER-SET settings when TRANSMIT is in text mode.  Include /TRANSPARENT"
+,
+"  to disable character-set translation in text mode (/TRANSPARENT implies",
+"  /TEXT).",
+" ",
+#endif /* NOCSETS */
+"  There can be no guarantee that the other computer will receive the file",
+"  correctly and completely.  Before you start the TRANSMIT command, you",
+"  must put the other computer in data collection mode, for example by",
+"  starting a text editor.  TRANSMIT may be interrupted by Ctrl-C.  Synonym:",
+"  XMIT.  See HELP SET TRANSMIT for further information.",
+"" };
+#endif /* NOXMIT */
+
+#ifndef NOCSETS
+static char *hxxxla[] = {
+"Syntax: TRANSLATE file1 cs1 cs2 [ file2 ]",
+"  Translates file1 from the character set cs1 into the character set cs2",
+"  and stores the result in file2.  The character sets can be any of",
+"  C-Kermit's file character sets.  If file2 is omitted, the translation",
+"  is displayed on the screen.  An appropriate intermediate character-set",
+"  is chosen automatically, if necessary.  Synonym: XLATE.  Example:",
+" ",
+"    TRANSLATE lasagna.lat latin1 italian lasagna.nrc",
+" ",
+"  Multiple files can be translated if file2 is a directory or device name,",
+"  rather than a filename, or if file2 is omitted.",
+"" };
+#endif /* NOCSETS */
+
+#ifndef NOSPL
+static char *hxxwai[] = {
+"Syntax: WAIT { number-of-seconds, hh:mm:ss } [ <what> ]",
+" ",
+"Examples:",
+"  wait 5 cd cts",
+"  wait 23:59:59 cd",
+" ",
+"  Waits up to the given number of seconds or the given time of day for the",
+"  specified item or event, which can be FILE, the name(s) of one or more",
+"  modem signals, or nothing.  If nothing is specified, WAIT acts like SLEEP.",
+"  If one or more modem signal names are given, Kermit waits for the specified"
+,
+"  modem signals to appear on the serial communication device.",
+"  Sets FAILURE if the signals do not appear in the given time or interrupted",
+"  from the keyboard during the waiting period.",
+" ",
+"Signals:",
+"  cd  = Carrier Detect;",
+"  dsr = Dataset Ready;",
+"  cts = Clear To Send;",
+"  ri  = Ring Indicate.",
+" ",
+"If you want Kermit to wait for a file event, then the syntax is:",
+" ",
+"  WAIT <time> FILE { CREATION, DELETION, MODIFICATION } <filename>",
+" ",
+"where <time> is as above, and <filename> is the name of a single file.",
+"Kermit waits up to the given amount of time for the specified event to occur",
+"with the specified file, succeeds if it does, fails if it doesn't.",
+"" };
+#endif /* NOSPL */
+
+static char *hxxwri[] = {
+"Syntax: WRITE name text",
+"  Writes the given text to the named log or file.  The text text may include",
+"  backslash codes, and is not terminated by a newline unless you include the",
+"  appropriate code.  The name parameter can be any of the following:",
+" ",
+"   DEBUG-LOG",
+"   ERROR (standard error)",
+#ifndef NOSPL
+"   FILE (the OPEN WRITE, OPEN !WRITE, or OPEN APPEND file, see HELP OPEN)",
+#endif /* NOSPL */
+"   PACKET-LOG",
+"   SCREEN (compare with ECHO)",
+#ifndef NOLOCAL
+"   SESSION-LOG",
+#endif /* NOLOCAL */
+"   TRANSACTION-LOG", "" };
+
+#ifndef NODIAL
+static char *hxxlook[] = { "Syntax: LOOKUP name",
+"  Looks up the given name in the dialing directory or directories, if any,",
+"  specified in the most recent SET DIAL DIRECTORY command.  Each matching",
+"  entry is shown, along with any transformations that would be applied to",
+"  portable-format entries based on your locale.  HELP DIAL, HELP SET DIAL",
+"  for further info.",
+""
+};
+
+static char *hxxansw[] = { "Syntax:  ANSWER [ <seconds> ]",
+#ifdef OS2
+"  Waits for a modem call to come in.  Prior SET MODEM TYPE and SET PORT",
+#else
+"  Waits for a modem call to come in.  Prior SET MODEM TYPE and SET LINE",
+#endif /* OS2 */
+"  required.  If <seconds> is 0 or not specified, Kermit waits forever or",
+"  until interrupted, otherwise Kermit waits the given number of seconds.",
+"  The ANSWER command puts the modem in autoanswer mode.  Subsequent DIAL",
+"  commands will automatically put it (back) in originate mode.  SHOW MODEM,",
+"  HELP SET MODEM for more info.",
+""
+};
+
+static char *hxxdial[] = { "Syntax:  DIAL phonenumber",
+"Example: DIAL 7654321",
+"  \
+Dials a number using an autodial modem.  First you must SET MODEM TYPE, then",
+#ifdef OS2
+"  SET PORT (or in Windows only, SET PORT TAPI instead of SET MODEM TYPE and",
+"  SET LINE), then SET SPEED. Then give the DIAL command, including the phone",
+#else
+"  SET LINE, then SET SPEED.  Then give the DIAL command, including the phone",
+#endif /* OS2 */
+"  number, for example:",
+" ",
+"   DIAL 7654321",
+#ifdef NETCONN
+" ",
+"  If the modem is on a network modem server, SET HOST first, then SET MODEM",
+"  TYPE, then DIAL.",
+#endif /* NETCONN */
+" ",
+"If you give the DIAL command interactively at the Kermit prompt, and the",
+"call is placed successfully, Kermit automatically enters CONNECT mode.",
+"If the DIAL command is given from a macro or command file, Kermit remains",
+"in command mode after the call is placed, successfully or not.  You can",
+"change this behavior with the SET DIAL CONNECT command.",
+" ",
+"If the phonenumber starts with a letter, and if you have used the SET DIAL",
+"DIRECTORY command to specify one or more dialing-directory files, Kermit",
+"looks it up in the given file(s); if it is found, the name is replaced by",
+"the number or numbers associated with the name.  If it is not found, the",
+"name is sent to the modem literally.",
+" ",
+"If the phonenumber starts with an equals sign (\"=\"), this forces the part",
+"after the = to be sent literally to the modem, even if it starts with a",
+"letter, without any directory lookup.",
+" ",
+"You can also give a list of phone numbers enclosed in braces, e.g:",
+" ",
+"  dial {{7654321}{8765432}{+1 (212 555-1212}}",
+" ",
+"(Each number is enclosed in braces and the entire list is also enclosed in",
+"braces.)  In this case, each number is tried until there is an answer.  The",
+"phone numbers in this kind of list can not be names of dialing directory",
+"entries.",
+" ",
+"A dialing directory is a plain text file, one entry per line:",
+" ",
+"  name  phonenumber  ;  comments",
+" ",
+"for example:",
+" ",
+"  work    9876543              ; This is a comment",
+"  e-mail  +1  (212) 555 4321   ; My electronic mailbox",
+"  germany +49 (511) 555 1234   ; Our branch in Hanover",
+" ",
+"If a phone number starts with +, then it must include country code and",
+"area code, and C-Kermit will try to handle these appropriately based on",
+"the current locale (HELP SET DIAL for further info); these are called",
+"PORTABLE entries.  If it does not start with +, it is dialed literally.",
+" ",
+"If more than one entry is found with the same name, Kermit dials all of",
+"them until the call is completed; if the entries are in portable format,",
+"Kermit dials them in cheap-to-expensive order: internal, then local, then",
+"long-distance, then international, based on its knowledge of your local",
+"country code and area code (see HELP SET DIAL).",
+" ",
+"Specify your dialing directory file(s) with the SET DIAL DIRECTORY command.",
+" ",
+#ifdef NETCONN
+"See also SET DIAL, SET MODEM, SET LINE, SET HOST, SET SPEED, REDIAL, and",
+"PDIAL.",
+#else
+"See also SET DIAL, SET MODEM, SET LINE, SET SPEED, PDIAL, and REDIAL.",
+#endif /* NETCONN */
+"" };
+
+#ifdef CK_TAPI
+static char *hxxtapi[] = {
+"TAPI CONFIGURE-LINE <tapi-line>",
+"  Displays the TAPI Configure Line Dialog box and allows you to",
+"  alter the default configuration for the specified <tapi-line>.",
+" ",
+"TAPI DIALING-PROPERTIES",
+"  Displays the TAPI Dialing Properties (locations) Dialog box.  The",
+"  Dialing rules may be changed and locations created and deleted.",
+"  When the dialog box is closed, K-95 imports the current Dialing",
+"  Properties' Location into the Kermit DIAL command settings.",
+""};
+
+static char *hxytapi[] = {
+"SET TAPI LINE <tapi-line>",
+"  Opens a TAPI device for use by Kermit.",
+" ",
+"SET TAPI MODEM-DIALING {ON, [OFF]}",
+"  If TAPI MODEM-DIALING is OFF when SET TAPI LINE is issued, Kermit opens",
+"  the TAPI device directly as a \"raw port\".  The device is unavailable to",
+"  other applications and Kermit performs dialing functions using its",
+"  built-in dialing and modem databases.  If TAPI MODEM-DIALING is ON, TAPI",
+"  handles all dialing functions and the port may be shared with other",
+"  applications when a call in not active.  When TAPI MODEM-DIALING is OFF,",
+"  SET MODEM TYPE TAPI Kermit uses the TAPI modem commands imported from the",
+"  Windows Registry during the previous SET TAPI LINE call.",
+" ",
+"SET TAPI LOCATION <tapi-location>",
+"  Specifies the TAPI location to make current for the entire system.  The",
+"  <tapi-location>'s dialing properties are imported into Kermit's SET DIAL",
+"  command database.",
+" ",
+"SET TAPI PHONE-NUMBER-CONVERSIONS {ON, OFF, [AUTO]}",
+"  Controls whether the phone number conversions are performed by TAPI (ON)",
+"  or by Kermit (OFF), or according the type of port that was selected",
+"  (AUTO); AUTO is the default, and is equivalent to ON if the current",
+"  LINE/PORT is a TAPI device and TAPI MODEM-DIALING is ON, OFF otherwise.",
+" ",
+"SET TAPI MODEM-LIGHTS {[ON], OFF}",
+"  Displays a modem lights indicator on the Windows 95 Taskbar.  Does nothing",
+"  in Windows NT 4.0.",
+" ",
+"SET TAPI MANUAL-DIALING {ON, [OFF]}",
+"  Displays a dialog box during dialing requesting that you manually dial the",
+"  phone before continuing.  Applies only when TAPI MODEM-DIALING is ON.",
+" ",
+"SET TAPI WAIT-FOR-CREDIT-CARD-TONE <seconds>",
+"  Some modems don't support the '$' (BONG) symbol during dialing, which",
+"  means \"wait for credit card tone before continuing.\"  If TAPI recognizes",
+"  the modem as one that does not support BONG, it replaces the '$' with",
+"  <seconds> worth of pauses.  The default is 8 seconds.  This command",
+"  applies only when TAPI MODEM-DIALING is ON",
+" ",
+"SET TAPI PRE-DIAL-TERMINAL {ON, [OFF]}",
+"SET TAPI POST-DIAL-TERMINAL {ON, [OFF]}",
+"  Displays a small terminal window that may be used to communicate with the",
+"  modem or the host prior to or immediately after dialing; applies only when",
+"  TAPI MODEM-DIALING is ON",
+" ",
+"SET TAPI INACTIVITY-TIMEOUT <minutes>",
+"  Specifies the number of minutes of inactivity that may go by before TAPI",
+"  disconnects the line.  The default is 0 which means disable this function.",
+"  Applies only when TAPI MODEM-DIALING is ON.",
+" ",
+"SET TAPI USE-WINDOWS-CONFIGURATION {ON, [OFF]}",
+"  Specifies whether the TAPI modem values for speed, parity, stop bits, flow",
+"  control, etc. are used in preference to the current values specified",
+"  within Kermit-95.",
+" ",
+""};
+#endif /* CK_TAPI */
+
+#endif /* NODIAL */
+
+#ifdef TNCODE
+static char *hmxxiks[] = {
+"Syntax: IKS [ switches ] [ host [ service ] ]",
+"  Establishes a new connection to an Internet Kermit Service daemon.",
+"  Equivalent to SET NETWORK TYPE TCP/IP, SET HOST host KERMIT /TELNET,",
+"  IF SUCCESS CONNECT.  If host is omitted, the previous connection (if any)",
+"  is resumed.  Depending on how Kermit has been built switches may be",
+"  available to require a secure authentication method and bidirectional",
+"  encryption.  See HELP SET TELNET for more info.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /AUTH:<type> is equivalent to SET TELNET AUTH TYPE <type> and",
+"   SET TELOPT AUTH REQUIRED with the following exceptions.  If the type",
+"   is AUTO, then SET TELOPT AUTH REQUESTED is executed and if the type",
+"   is NONE, then SET TELOPT AUTH REFUSED is executed.",
+" ",
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+" /ENCRYPT:<type> is equivalent to SET TELNET ENCRYPT TYPE <type>",
+"   and SET TELOPT ENCRYPT REQUIRED REQUIRED with the following exceptions.",
+"   If the type is AUTO then SET TELOPT AUTH REQUESTED REQUESTED is executed",
+"   and if the type is NONE then SET TELOPT ENCRYPT REFUSED REFUSED is",
+"   executed.",
+" ",
+#endif /* CK_ENCRYPTION */
+" /USERID:[<name>]",
+"   This switch is equivalent to SET LOGIN USERID <name> or SET TELNET",
+"   ENVIRONMENT USER <name>.  If a string is given, it sent to host during",
+"   Telnet negotiations; if this switch is given but the string is omitted,",
+"   no user ID is sent to the host.  If this switch is not given, your",
+"   current USERID value, \\v(userid), is sent.  When a userid is sent to the",
+"   host it is a request to login as the specified user.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /PASSWORD:[<string>]",
+"   This switch is equivalent to SET LOGIN PASSWORD.  If a string is given,",
+"   it is treated as the password to be used (if required) by any Telnet",
+"   Authentication protocol (Kerberos Ticket retrieval, Secure Remote",
+"   Password, or X.509 certificate private key decryption.)  If no password",
+"   switch is specified a prompt is issued to request the password if one",
+"   is required for the negotiated authentication method.",
+#endif /* CK_AUTHENTICATION */
+""};
+
+static char *hmxxtel[] = {
+"Syntax: TELNET [ switches ] [ host [ service ] ]",
+"  Equivalent to SET NETWORK TYPE TCP/IP, SET HOST host [ service ] /TELNET,",
+"  IF SUCCESS CONNECT.  If host is omitted, the previous connection (if any)",
+"  is resumed.  Depending on how Kermit has been built switches may be",
+"  available to require a secure authentication method and bidirectional",
+"  encryption.  See HELP SET TELNET for more info.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /AUTH:<type> is equivalent to SET TELNET AUTH TYPE <type> and",
+"   SET TELOPT AUTH REQUIRED with the following exceptions.  If the type",
+"   is AUTO, then SET TELOPT AUTH REQUESTED is executed and if the type",
+"   is NONE, then SET TELOPT AUTH REFUSED is executed.",
+" ",
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+" /ENCRYPT:<type> is equivalent to SET TELNET ENCRYPT TYPE <type>",
+"   and SET TELOPT ENCRYPT REQUIRED REQUIRED with the following exceptions.",
+"   If the type is AUTO then SET TELOPT AUTH REQUESTED REQUESTED is executed",
+"   and if the type is NONE then SET TELOPT ENCRYPT REFUSED REFUSED is",
+"   executed.",
+" ",
+#endif /* CK_ENCRYPTION */
+" /USERID:[<name>]",
+"   This switch is equivalent to SET LOGIN USERID <name> or SET TELNET",
+"   ENVIRONMENT USER <name>.  If a string is given, it sent to host during",
+"   Telnet negotiations; if this switch is given but the string is omitted,",
+"   no user ID is sent to the host.  If this switch is not given, your",
+"   current USERID value, \\v(userid), is sent.  When a userid is sent to the",
+"   host it is a request to login as the specified user.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /PASSWORD:[<string>]",
+"   This switch is equivalent to SET LOGIN PASSWORD.  If a string is given,",
+"   it is treated as the password to be used (if required) by any Telnet",
+"   Authentication protocol (Kerberos Ticket retrieval, Secure Remote",
+"   Password, or X.509 certificate private key decryption.)  If no password",
+"   switch is specified a prompt is issued to request the password if one",
+"   is required for the negotiated authentication method.",
+#endif /* CK_AUTHENTICATION */
+""};
+
+static char *hxtopt[] = {
+"TELOPT { AO, AYT, BREAK, CANCEL, EC, EL, EOF, EOR, GA, IP, DMARK, NOP, SE,",
+"         SUSP, SB [ option ], DO [ option ], DONT [ option ],",
+"         WILL [ option ], WONT [option] }",
+"  This command lets you send all the Telnet protocol commands.  Note that",
+"  certain commands do not require a response, and therefore can be used as",
+"  nondestructive \"probes\" to see if the Telnet session is still open;",
+"  e.g.:",
+" ",
+"    set host xyzcorp.com",
+"    ...",
+"    telopt nop",
+"    telopt nop",
+"    if fail stop 1 Connection lost",
+" ",
+"  TELOPT NOP is sent twice because the failure of the connection will not",
+"  be detected until the second send is attempted.  This command is meant",
+"  primarily as a debugging tool for the expert user.",
+""};
+#endif /* TNCODE */
+
+#endif /* NOHELP */
+
+/*  D O H L P  --  Give a help message  */
+
+_PROTOTYP( int dohset, (int) );
+#ifndef NOCMDL
+_PROTOTYP( int dohopts, (void) );
+#endif /* NOCMDL */
+#ifndef NOSPL
+_PROTOTYP( int dohfunc, (int) );
+extern struct keytab fnctab[];
+extern int nfuncs;
+#endif /* NOSPL */
+#ifdef OS2
+#ifndef NOKVERBS
+_PROTOTYP( int dohkverb, (int) );
+extern struct keytab kverbs[];
+extern int nkverbs;
+#endif /* NOKVERBS */
+#endif /* OS2 */
+
+#ifndef NOSPL
+static char * hxxdcl[] = {
+"Syntax: ARRAY verb operands...",
+" ",
+"Declares arrays and performs various operations on them.  Arrays have",
+"the following syntax:",
+" ",
+"  \\&a[n]",
+" ",
+"where \"a\" is a letter and n is a number or a variable with a numeric value",
+"or an arithmetic expression.  The value of an array element can be anything",
+"at all -- a number, a character, a string, a filename, etc.",
+" ",
+"The following ARRAY verbs are available:",
+" ",
+"[ ARRAY ] DECLARE arrayname[n] [ = initializers... ]",
+"  Declares an array of the given size, n.  The resulting array has n+1",
+"  elements, 0 through n.  Array elements can be used just like any other",
+"  variables.  Initial values can be given for elements 1, 2, ... by",
+"  including = followed by one or more values separated by spaces.  If you",
+"  omit the size, the array is sized according to the number of initializers;",
+"  if none are given the array is destroyed and undeclared if it already",
+"  existed.  The ARRAY keyword is optional.  Synonym: [ ARRAY ] DCL.",
+" ",
+"[ ARRAY ] UNDECLARE arrayname",
+"  Destroys and undeclares the given array.  Synonym: ARRAY DESTROY.",
+" ",
+"ARRAY SHOW [ arrayname ]",
+"  Displays the contents of the given array.  A range specifier can be",
+"  included to display a segment of the array, e.g. \"array show \\&a[1:24].\""
+,
+"  If the arrayname is omitted, all declared arrays are listed, but their",
+"  contents is not shown.  Synonym: SHOW ARRAY.",
+" ",
+"ARRAY CLEAR arrayname",
+"  Clears all elements of the array, i.e. sets them to empty values.",
+"  You may include a range specifier to clear a segment of the array rather",
+"  than the whole array, e.g. \"array clear \\%a[22:38]\"",
+" ",
+"ARRAY SET arrayname value",
+"  Sets all elements of the array to the given value.  You may specify a",
+"  range to set a segment of the array, e.g. \"array set \\%a[2:9] 0\"",
+" ",
+"ARRAY RESIZE arrayname number",
+"  Changes the size of the given array, which must already exist, to the",
+"  number given.  If the number is smaller than the current size, the extra",
+"  elements are discarded; if it is larger, new empty elements are added.",
+" ",
+"ARRAY COPY array1 array2",
+"  Copys array1 to array2.  If array2 has not been declared, it is created",
+"  automatically.  Range specifiers may be given on one or both arrays.",
+" ",
+"ARRAY LINK array1 arra2",
+"  Makes array1 a link to array2.",
+" ",
+"[ ARRAY ] SORT [ switches ] array-name [ array2 ]",
+"  Sorts the given array lexically according to the switches.  Element 0 of",
+"  the array is excluded from sorting by default.  The ARRAY keyword is",
+"  optional.  If a second array name is given, that array is sorted according",
+"  to the first one.  Switches:",
+" ",
+"  /CASE:{ON,OFF}",
+"    If ON, alphabetic case matters; if OFF it is ignored.  If this switch is",
+"    omitted, the current SET CASE setting applies.",
+" ",
+"  /KEY:number",
+"    \
+Position (1-based column number) at which comparisons begin, 1 by default.",
+" ",
+"  /NUMERIC",
+"    Specifies a numeric rather than lexical sort.",
+" ",
+"  /RANGE:low[:high]",
+"    The range of elements, low through high, to be sorted.  If this switch",
+"    is not given, elements 1 through the dimensioned size are sorted.  If",
+"    :high is omitted, the dimensioned size is used.  To include element 0 in",
+"    a sort, use /RANGE:0 (to sort the whole array) or /RANGE:0:n (to sort",
+"    elements 0 through n).  You can use a range specifier in the array name",
+"    instead of the /RANGE switch.",
+" ",
+"  /REVERSE",
+"    Sort in reverse order.  If this switch is not given, the array is sorted",
+"    in ascending order.",
+" ",
+"Various functions are available for array operations; see HELP FUNCTION for",
+"details.  These include \\fdimension(), \\farraylook(), \\ffiles(), \
+\\fsplit(),",
+"and many more.",
+""};
+#endif /* NOSPL */
+
+#ifdef ZCOPY
+static char * hmxxcpy[] = {
+"Syntax: COPY [ switches ] file1 file2",
+"  Copies the source file (file1) to the destination file (file2).  If file2",
+"  is a directory, file1 can contain wildcards to denote a group of files to",
+"  be copied to the given directory.  Switches:",
+" ",
+"  /LIST",
+"    Print the filenames and status while copying.  Synonyms: /LOG, /VERBOSE",
+" ",
+"  /NOLIST",
+"    Copy silently (default). Synonyms: /NOLOG, /QUIET",
+" ",
+"  /SWAP-BYTES",
+"    Swap bytes while copying.",
+#ifndef NOSPL
+" ",
+"  /FROMB64",
+"    Convert from Base64 encoding while copying.",
+" ",
+"  /TOB64",
+"    Convert to Base64 encoding while copying.",
+#endif /* NOSPL */
+""
+};
+#endif /* ZCOPY */
+
+#ifndef NOFRILLS
+static char * hmxxren[] = {
+#ifdef LOCUS
+"  If LOCUS is REMOTE or LOCUS is AUTO and you have an FTP connection,",
+"  this command is equivalent to REMOTE RENAME (RREN).  Otherwise:",
+" ",
+#endif /* LOCUS */
+"Syntax: RENAME [ switches ] name1 name2",
+"  Renames the source file (name1) to the target name2.  If name2 is a",
+"  directory, name1 is allowed to contain wildcards, and the file(s) matching",
+"  name1 are moved to directory name2, subject to rules of the underlying",
+"  operating system regarding renaming across disk boundaries, etc.  If name2",
+"  is not a directory, name1 may not include wildcards, and the file whose",
+"  name is name1 is renamed to name2.  Switches:",
+" ",
+"  /LIST",
+"    Print the filenames and status while renaming.  Synonyms: /LOG, /VERBOSE",
+" ",
+"  /NOLIST",
+"    Rename silently (default). Synonyms: /NOLOG, /QUIET",
+""
+};
+#endif /* NOFRILLS */
+
+static char *
+cmdlhlp[] = {
+"Command-line options are given after the program name in the system",
+"command that you use to start Kermit.  Example:",
+" ",
+" kermit -i -s oofa.exe",
+" ",
+"tells Kermit to send (-s) the file oofa.exe in binary (-i) mode.",
+" ",
+"Command-line options are case-sensitive; \"-s\" is different from \"-S\".",
+#ifdef VMS
+"In VMS, uppercase options must be enclosed in doublequotes: ",
+" ",
+" $ kermit \"-Y\" \"-S\" -s oofa.txt ",
+#endif /* VMS */
+" ",
+"If any \"action options\" are included on the command line, Kermit exits",
+"after executing its command-line options.  If -S is included, or no action",
+"options were given, Kermit enters its interactive command parser and",
+"issues its prompt.",
+" ",
+"Command-line options are single characters preceded by dash (-).  Some",
+"require an \"argument,\" others do not.  If an argument contains spaces, it",
+"must be enclosed in doublequotes:",
+" ",
+" kermit -s \"filename with spaces\"",
+" ",
+"\
+An option that does not require an argument can be bundled with other options:"
+,
+" ",
+" kermit -Qis oofa.exe",
+" ",
+"Exceptions to the rules:",
+" ",
+" . If the first command-line option is a filename, Kermit executes commands",
+"   from the file.  Additional command-line options can follow the filename.",
+" ",
+" . The special option \"=\" (equal sign) or \"--\" (double hyphen) means to",
+"   treat the rest of the command line as data, rather than commands; this",
+"   data is placed in the argument vector array, \\&@[], along with the other",
+"   items on the command line, and also in the top-level \\%1..\\%9 variables."
+,
+" ",
+#ifdef KERBANG
+" . A similar option \"+\" (plus sign) means: the name of a Kermit script",
+"   file follows.  This file is to be executed, and its name assigned to \\%0",
+"   and \\&_[0].  All subsequent command-line arguments are to be ignored by",
+"   Kermit but made available to the script as \\%1, \\%2, ..., as well as",
+"   in the argument-vector arrays.  The initialization file is not executed",
+"   automatically in this case.",
+" ",
+#endif /* KERBANG */
+" . The -s option can accept multiple filenames, separated by spaces.",
+" ",
+" . the -j and -J options allow an optional second argument, the TCP port",
+"   name or number.",
+" ",
+"Type \"help options all\" to list all the command-line options.",
+"Type \"help option x\" to see the help message for option x.",
+" ",
+"Kermit also offers a selection of \"extended command-line\" options.",
+"These begin with two dashes, followed by a keyword, and then, if the option",
+"has arguments, a colon (:) or equal sign (=) followed by the argument.",
+"Unlike single-letter options, extended option keywords aren't case sensitive",
+"and they can be abbreviated to any length that still distinguishes them from",
+"other extended-option keywords.  Example:",
+" ",
+"  kermit --banner:oofa.txt",
+" ",
+"which designates the file oofa.txt to be printed upon startup, rather than",
+"the built-in banner (greeting) text.  To obtain a list of available",
+"extended options, type \"help extended-options ?\".  To get help about all",
+"extended options, type \"help extended-options\".  To get help about a",
+"particular extended option, type \"help extended-option xxx\", where \"xxx\"",
+"is the option keyword.",
+#ifdef COMMENT
+#ifndef NOIKSD
+" ",
+"At present, most of the extended options apply only to the Internet Kermit",
+"Service Daemon (IKSD).  Type \"help iksd\" for details.",
+#endif /* NOIKSD */
+#endif /* COMMENT */
+""
+};
+
+#ifndef NOHELP
+#ifndef NOCMDL
+int
+doxopts() {
+    extern char * xopthlp[], * xarghlp[];
+    extern struct keytab xargtab[];
+    extern int nxargs;
+    int i, x, y, n = 0;
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+    ttgcwsz();
+#else /* OS2 */
+    /* Check whether window size changed */
+    if (ttgwsiz() > 0) {
+        if (tt_rows > 0 && tt_cols > 0) {
+            cmd_rows = tt_rows;
+            cmd_cols = tt_cols;
+        }
+    }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+    y = cmkey(xargtab,
+              nxargs,
+              "Extended argument without the \"--\" prefix",
+              "",
+              xxstring
+              );
+    if (y == -3) {
+       printf("\n");
+        if ((x = cmcfm()) < 0)
+         return(x);
+        for (i = 0; i <= XA_MAX; i++) {
+            if (xopthlp[i]) {
+                printf("%s\n",xopthlp[i]);
+                printf("   %s\n",xarghlp[i]);
+                printf("\n");
+                n += 3;
+                if (n > (cmd_rows - 6)) {
+                    if (!askmore())
+                      return(0);
+                    else
+                      n = 0;
+                }
+            }
+        }
+        return(1);
+    } else if (y < 0)
+      return(y);
+    if ((x = cmcfm()) < 0)
+      return(x);
+    printf("\n%s\n",xopthlp[y]);
+    printf("   %s\n\n",xarghlp[y]);
+    return(1);
+}
+
+int
+dohopts() {
+    int i, n, x, y, z, all = 0, msg = 0;
+    char *s;
+    extern char *opthlp[], *arghlp[];
+    extern char * xopthlp[], * xarghlp[];
+    extern int optact[];
+    if ((x = cmtxt("A command-line option character,\n\
+or the word ALL, or carriage return for an overview",
+                   "", &s, xxstring)) < 0)
+      return(x);
+    if (!*s)
+      msg = 1;
+    else if (!strcmp(s,"all") || (!strcmp(s,"ALL")))
+      all = 1;
+    else if (*s == '-')                 /* Be tolerant of leading hyphen */
+      s++;
+    if (!all && (int)strlen(s) > 1) {
+        printf("?A single character, please, or carriage to list them all.\n");
+        return(-9);
+    }
+    if (all) {
+        y = 33;
+        z = 127;
+    } else {
+        y = *s;
+        z = (y == 0) ? 127 : y;
+        if (y == 0) y = 33;
+    }
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+    ttgcwsz();
+#else /* OS2 */
+    /* Check whether window size changed */
+    if (ttgwsiz() > 0) {
+        if (tt_rows > 0 && tt_cols > 0) {
+            cmd_rows = tt_rows;
+            cmd_cols = tt_cols;
+        }
+    }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+    printf("\n");
+    for (i = 0, n = 1; msg != 0 && *cmdlhlp[i]; i++) {
+        printf("%s\n",cmdlhlp[i]);
+        if (++n > (cmd_rows - 3)) {
+           if (!askmore())
+             return(0);
+           else
+             n = 0;
+        }
+    }
+    if (all) {
+        printf("The following command-line options are available:\n\n");
+        n += 2;
+    }
+    for (i = y; msg == 0 && i <= z; i++) {
+        if (!opthlp[i])
+          continue;
+        if (arghlp[i]) {                /* Option with arg */
+            printf(" -%c <arg>%s\n",(char)i,(optact[i]?" (action option)":""));
+
+            printf("     %s\n",opthlp[i]);
+            printf("     Argument: %s\n\n",arghlp[i]);
+            x = 4;
+        } else {                        /* Option without arg */
+            printf(" -%c  %s%s\n",
+                   (char)i, opthlp[i],
+                   (optact[i]?" (action option)":"")
+                  );
+            printf("     Argument: (none)\n\n");
+            x = 3;
+        }
+        n += x;
+        if (n > (cmd_rows - x - 1)) {
+            if (!askmore())
+              return(0);
+           else
+              n = 0;
+        }
+    }
+    if (all) {                         /* Jeff, Jan 2003 */
+        printf("\n");
+        if (++n >= cmd_rows) {
+            if (!askmore())
+              return(0);
+           else
+              n = 0;
+        }
+        printf("The following extended options are available:\n");
+        if (++n >= cmd_rows) {
+            if (!askmore())
+              return(0);
+           else
+              n = 0;
+        }
+        printf("\n");
+        if (++n >= cmd_rows) {
+            if (!askmore())
+              return(0);
+           else
+              n = 0;
+        }
+        for (i = 0; i <= XA_MAX; i++) {
+            if (xopthlp[i]) {
+                printf("%s\n",xopthlp[i]);
+                printf("   %s\n",xarghlp[i]);
+                printf("\n");
+                n += 3;
+                if (n > (cmd_rows - 4)) {
+                    if (!askmore())
+                     return(0);
+                    else
+                     n = 0;
+                }
+            }
+        }
+    }
+    return(1);
+}
+#endif /* NOCMDL */
+#endif /* NOHELP */
+
+#ifdef CKCHANNELIO
+static char * hxxfile[] = {
+"Syntax: FILE <subcommand> [ switches ] <channel> [ <data> ]",
+"  Opens, closes, reads, writes, and manages local files.",
+" ",
+"The FILE commands are:",
+" ",
+"  FILE OPEN   (or FOPEN)   -- Open a local file.",
+"  FILE CLOSE  (or FCLOSE)  -- Close an open file.",
+"  FILE READ   (or FREAD)   -- Read data from an open file.",
+"  FILE WRITE  (or FWRITE)  -- Write data to an open file.",
+"  FILE LIST   (or FLIST)   -- List open files.",
+"  FILE STATUS (or FSTATUS) -- Show status of a channel.",
+"  FILE REWIND (or FREWIND) -- Rewind an open file",
+"  FILE COUNT  (or FCOUNT)  -- Count lines or bytes in an open file",
+"  FILE SEEK   (or FSEEK)   -- Seek to specified spot in an open file.",
+"  FILE FLUSH  (or FFLUSH)  -- Flush output buffers for an open file.",
+" ",
+"Type HELP FILE OPEN or HELP FOPEN for details about FILE OPEN;",
+"type HELP FILE CLOSE or HELP FCLOSE for details about FILE CLOSE, and so on.",
+" ",
+"The following variables are related to the FILE command:",
+" ",
+"  \\v(f_max)     -- Maximum number of files that can be open at once",
+"  \\v(f_error)   -- Completion code of most recent FILE command or function",
+"  \\v(f_count)   -- Result of most recent FILE COUNT command",
+" ",
+"The following functions are related to the FILE command:",
+" ",
+"  \\F_eof()      -- Check if channel is at EOF",
+"  \\F_pos()      -- Get channel read/write position (byte number)",
+"  \\F_line()     -- Get channel read/write position (line number)",
+"  \\F_handle()   -- Get file handle",
+"  \\F_status()   -- Get channel status",
+"  \\F_getchar()  -- Read character",
+"  \\F_getline()  -- Read line",
+"  \\F_getblock() -- Read block",
+"  \\F_putchar()  -- Write character",
+"  \\F_putline()  -- Write line",
+"  \\F_putblock() -- Write block",
+"  \\F_errmsg()   -- Error message from most recent FILE command or function",
+" ",
+"Type HELP <function-name> for information about each one.",
+""
+};
+
+static char * hxxf_op[] = {
+"Syntax: FILE OPEN [ switches ] <variable> <filename>",
+"  Opens the file indicated by <filename> in the mode indicated by the",
+"  switches, if any, or if no switches are included, in read-only mode, and",
+"  assigns a channel number for the file to the given variable.",
+"  Synonym: FOPEN.  Switches:",
+" ",
+"/READ",
+"  Open the file for reading.",
+" ",
+"/WRITE",
+"  Open the file for writing.  If /READ was not also specified, this creates",
+"  a new file.  If /READ was specifed, the existing file is preserved, but",
+"  writing is allowed.  In both cases, the read/write pointer is initially",
+"  at the beginning of the file.",
+" ",
+"/APPEND",
+"  If the file does not exist, create a new file and open it for writing.",
+"  If the file exists, open it for writing, but with the write pointer",
+"  positioned at the end.",
+" ",
+"/BINARY",
+#ifdef VMS
+"  Opens the file in binary mode to inhibit end-of-line conversions.",
+#else
+#ifdef OS2
+"  Opens the file in binary mode to inhibit end-of-line conversions.",
+#else
+#ifdef UNIX
+"  This option is ignored in UNIX.",
+#else
+"  This option is ignored on this platform.",
+#endif /* UNIX */
+#endif /* OS2 */
+#endif /* VMS */
+" ",
+"Switches can be combined in an way that makes sense and is supported by the",
+"underlying operating system.",
+""
+};
+
+static char * hxxf_cl[] = {
+"Syntax: FILE CLOSE <channel>",
+"  Closes the file on the given channel if it was open.",
+"  Also see HELP FILE OPEN.  Synonym: FCLOSE.",
+""
+};
+
+static char * hxxf_fl[] = {
+"Syntax: FILE FLUSH <channel>",
+"  Flushes output buffers on the given channel if it was open, forcing",
+"  all material previously written to be committed to disk.  Synonym: FFLUSH.",
+"  Also available as \\F_flush().",
+""
+};
+
+static char * hxxf_li[] = {
+"Syntax: FILE LIST",
+"  Lists the channel number, name, modes, and position of each file opened",
+"  with FILE OPEN.  Synonym: FLIST.",
+""
+};
+
+static char * hxxf_re[] = {
+"Syntax: FILE READ [ switches ] <channel> [ <variable> ]",
+"  Reads data from the file on the given channel number into the <variable>,",
+"  if one was given; if no variable was given, the result is printed on",
+"  the screen.  The variable should be a macro name rather than a \\%x",
+"  variable or array element if you want backslash characters in the file to",
+"  be taken literally.  Synonym: FREAD.  Switches:",
+" ",
+"/LINE",
+"  Specifies that a line of text is to be read.  A line is defined according",
+"  to the underlying operating system's text-file format.  For example, in",
+"  UNIX a line is a sequence of characters up to and including a linefeed.",
+"  The line terminator (if any) is removed before assigning the text to the",
+"  variable.  If no switches are included with the FILE READ command, /LINE",
+"  is assumed.",
+" ",
+"/SIZE:number",
+"  Specifies that the given number of bytes (characters) is to be read.",
+"  This gives a semblance of \"record i/o\" for files that do not necessarily",
+"  contain lines.  The resulting block of characters is assigned to the",
+"  variable without any editing.",
+" ",
+"/CHARACTER",
+"  Equivalent to /SIZE:1.  If FILE READ /CHAR succeeds but the <variable> is",
+"  empty, this indicates a NUL byte was read.",
+" ",
+"/TRIM",
+"  Tells Kermit to trim trailing whitespace when used with /LINE.  Ignored",
+"  if used with /CHAR or /SIZE.",
+" ",
+"/UNTABIFY",
+"  Tells Kermit to convert tabs to spaces (assuming tabs set every 8 spaces)",
+"  when used with /LINE.  Ignored if used with /CHAR or /SIZE.",
+" ",
+"Synonym: FREAD.",
+"Also available as \\F_getchar(), \\F_getline(), \\F_getblock().",
+""
+};
+
+static char * hxxf_rw[] = {
+"Syntax: FILE REWIND <channel>",
+"  If the channel is open, moves the read/write pointer to the beginning of",
+"  the file.  Equivalent to FILE SEEK <channel> 0.  Synonym: FREWIND.",
+"  Also available as \\F_rewind().",
+""
+};
+
+static char * hxxf_se[] = {
+"Syntax: FILE SEEK [ switches ] <channel> { [{+,-}]<number>, EOF }",
+"  Switches are /BYTE, /LINE, /RELATIVE, ABSOLUTE.",
+"  Moves the file pointer for this file to the given position in the",
+"  file.  Subsequent FILE READs or WRITEs will take place at that position.",
+"  If neither the /RELATIVE nor /ABSOLUTE switch is given, an unsigned",
+"  <number> is absolute; a signed number is relative.  EOF means to move to",
+"  the end of the file.  Synonym: FSEEK.  Also available as \\F_seek().",
+""
+};
+
+static char * hxxf_st[] = {
+"Syntax: FILE STATUS <channel>",
+"  If the channel is open, this command shows the name of the file, the",
+"  switches it was opened with, and the current read/write position.",
+"  Synonym: FSTATUS",
+""
+};
+
+static char * hxxf_co[] = {
+"Syntax: FILE COUNT [ { /BYTES, /LINES, /LIST, /NOLIST } ] <channel>",
+"  If the channel is open, this command prints the nubmer of bytes (default)",
+"  or lines in the file if at top level or if /LIST is included; if /NOLIST",
+"  is given, the result is not printed.  In all cases the result is assigned",
+"  to \\v(f_count).  Synonym: FCOUNT",
+""
+};
+
+static char * hxxf_wr[] = {
+"FILE WRITE [ switches ] <channel> <text>",
+"  Writes the given text to the file on the given channel number.  The <text>",
+"  can be literal text or a variable, or any combination.  If the text might",
+"  contain leading or trailing spaces, it must be enclosed in braces if you",
+"  want to preserve them.  Synonym: FWRITE.  Switches:",
+" ",
+"/LINE",
+"  Specifies that an appropriate line terminator is to be added to the",
+"  end of the <text>.  If no switches are included, /LINE is assumed.",
+" ",
+"/SIZE:number",
+"  Specifies that the given number of bytes (characters) is to be written.",
+"  If the given <text> is longer than the requested size, it is truncated;",
+"  if is shorter, it is padded according /LPAD and /RPAD switches.  Synonym:",
+"  /BLOCK.",
+" ",
+"/LPAD[:value]",
+"  If /SIZE was given, but the <text> is shorter than the requested size,",
+"  the text is padded on the left with sufficient copies of the character",
+"  whose ASCII value is given to write the given length.  If no value is",
+"  specified, 32 (the code for Space) is used.  The value can also be 0 to",
+"  write the indicated number of NUL bytes.  If /SIZE was not given, this",
+"  switch is ignored.",
+" ",
+"/RPAD[:value]",
+"  Like LPAD, but pads on the right.",
+" ",
+"/STRING",
+"  Specifies that the <text> is to be written as-is, with no terminator added."
+,
+" ",
+"/CHARACTER",
+"  Specifies that one character should be written.  If the <text> is empty or",
+"  not given, a NUL character is written; otherwise the first character of",
+"  <text> is given.",
+" ",
+"Synonym FWRITE.",
+"Also available as \\F_putchar(), \\F_putline(), \\F_putblock().",
+""
+};
+
+static int
+dohfile(cx) int cx; {
+    extern struct keytab fctab[];
+    extern int nfctab;
+    int x;
+    if (cx == XXFILE) {                 /* FILE command was given */
+        /* Get subcommand */
+        if ((cx = cmkey(fctab,nfctab,"Operation","",xxstring)) < 0) {
+            if (cx == -3) {
+                if ((x = cmcfm()) < 0)
+                  return(x);
+                cx = XXFILE;
+            } else
+              return(cx);
+        }
+        if ((x = cmcfm()) < 0)
+          return(x);
+        switch (cx) {
+          case FIL_CLS: cx = XXF_CL; break;
+          case FIL_FLU: cx = XXF_FL; break;
+          case FIL_LIS: cx = XXF_LI; break;
+          case FIL_OPN: cx = XXF_OP; break;
+          case FIL_REA: cx = XXF_RE; break;
+          case FIL_REW: cx = XXF_RW; break;
+          case FIL_SEE: cx = XXF_SE; break;
+          case FIL_STA: cx = XXF_ST; break;
+          case FIL_WRI: cx = XXF_WR; break;
+          case FIL_COU: cx = XXF_CO; break;
+        }
+    }
+    switch (cx) {
+      case XXFILE: return(hmsga(hxxfile));
+      case XXF_CL: return(hmsga(hxxf_cl));
+      case XXF_FL: return(hmsga(hxxf_fl));
+      case XXF_LI: return(hmsga(hxxf_li));
+      case XXF_OP: return(hmsga(hxxf_op));
+      case XXF_RE: return(hmsga(hxxf_re));
+      case XXF_RW: return(hmsga(hxxf_rw));
+      case XXF_SE: return(hmsga(hxxf_se));
+      case XXF_ST: return(hmsga(hxxf_st));
+      case XXF_WR: return(hmsga(hxxf_wr));
+      case XXF_CO: return(hmsga(hxxf_co));
+      default:
+        return(-2);
+    }
+}
+#endif /* CKCHANNELIO */
+
+int
+dohlp(xx) int xx; {
+    int x,y;
+
+    debug(F101,"DOHELP xx","",xx);
+    if (xx < 0) return(xx);
+
+#ifdef NOHELP
+    if ((x = cmcfm()) < 0)
+      return(x);
+    printf("\n%s, Copyright (C) 1985, 2004,",versio);
+#ifndef NOIKSD
+    if (inserver)
+      return(hmsga(tophlpi));
+    else
+#endif /* IKSD */
+      return(hmsga(tophlp));
+
+#else /* help is available */
+
+    if (helpfile)
+      return(dotype(helpfile,xaskmore,0,0,NULL,0,NULL,0,0,NULL,0));
+
+#ifdef CKCHANNELIO
+    if (xx == XXFILE)
+      return(dohfile(xx));
+    else if (xx == XXF_RE || xx == XXF_WR || xx == XXF_OP ||
+             xx == XXF_CL || xx == XXF_SE || xx == XXF_RW ||
+             xx == XXF_FL || xx == XXF_LI || xx == XXF_ST || xx == XXF_CO)
+      return(dohfile(xx));
+#endif /* CKCHANNELIO */
+
+    switch (xx) {
+
+#ifndef NOSPL
+case XXASS:                             /* ASSIGN */
+    return(hmsga(hxxass));
+
+case XXASK:                             /* ASK */
+case XXASKQ:                            /* ASKQ */
+    return(hmsga(hxxask));
+
+case XXAPC:
+    return(hmsg("Syntax: APC text\n\
+  Echoes the text within a VT220/320/420 Application Program Command."));
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+case XXBUG:
+    return(hmsg("Describes how to get technical support."));
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+case XXBEEP:
+#ifdef OS2
+    return(hmsg("Syntax: BEEP [ { ERROR, INFORMATION, WARNING } ]\n\
+  Generates a bell according to the current settings.  If SET BELL is set to\n\
+  \"system-sounds\" then the appropriate System Sound will be generated.\n\
+  Default is INFORMATION."));
+#else /* OS2 */
+    return(hmsg("Syntax: BEEP\n\
+Sends a BEL character to your terminal."));
+#endif /* OS2 */
+#endif /* NOSPL */
+
+case XXBYE:                             /* BYE */
+    return(hmsg(hmxxbye));
+
+case XXCHK:                             /* check */
+    return(hmsg("\
+Syntax: CHECK name\n\
+  Checks\
+  to see if the named feature is included in this version of Kermit.\n\
+  To list the features you can check, type \"check ?\"."));
+
+#ifndef NOFRILLS
+case XXCLE:                             /* clear */
+    return(hmsga(hmxxcle));
+#endif /* NOFRILLS */
+
+case XXCLO:                             /* close */
+    return(hmsga(hmxxclo));
+
+case XXCOM:                             /* comment */
+#ifndef STRATUS /* Can't use # for comments in Stratus VOS */
+    return(hmsg("\
+Syntax: COMMENT text\n\
+Example: COMMENT - this is a comment.\n\
+  Introduces a comment.  Beginning of command line only.  Commands may also\n\
+  have trailing comments, introduced by ; or #."));
+#else
+    return(hmsg("\
+Syntax: COMMENT text\n\
+Example: COMMENT - this is a comment.\n\
+  Introduces a comment.  Beginning of command line only.  Commands may also\n\
+  have trailing comments, introduced by ; (semicolon)."));
+#endif /* STRATUS */
+
+#ifndef NOLOCAL
+case XXCON:                             /* CONNECT */
+case XXCQ:                              /* CQ == CONNECT /QUIETLY */
+    hmsga(hmxxcon);
+    printf("Your escape character is Ctrl-%c (ASCII %d, %s)\r\n",
+           ctl(escape), escape, (escape == 127 ? "DEL" : ccntab[escape]));
+    return(0);
+#endif /* NOLOCAL */
+
+#ifdef ZCOPY
+case XXCPY:
+    return(hmsga(hmxxcpy));
+#endif /* ZCOPY */
+
+#ifdef NT
+case XXLINK:
+return(hmsg(
+"  LINK source destination\n\
+   creates a hard link to the file specified by source to the filename\n\
+   specified by destination.  Hard links are only supported on NTFS.\n\
+   destination can either be a filename or a directory.  source may\n\
+   contain wildcards if destination is a directory."));
+#endif /* NT */
+
+#ifndef NOFRILLS
+case XXLREN:                            /* LRENAME */
+    return(hmsg(
+"  LRENAME is an alias for the RENAME command forcing it to execute\n\
+  on the local computer.  Also see: RENAME, RRENAME, SET LOCUS."));
+
+case XXREN:
+    return(hmsga(hmxxren));
+#endif /* NOFRILLS */
+
+case XXCDUP:                             /* CDUP */
+case XXLCDU:
+    return(hmsg(
+"Change working directory to the one just above the current one."));
+
+case XXLCWD:
+    return(hmsg(
+"  LCD (LCWD) is an alias for the CD (CWD) command forcing it to execute\n\
+  on the local computer.  Also see: CD, CDUP, RCD, SET LOCUS."));
+
+case XXCWD:                             /* CD / CWD */
+    return(hmsga(hmxxcwd));
+
+#ifndef NOSPL
+case XXKCD:
+    return(hmsga(hmxxkcd));
+
+case XXARRAY:
+case XXDCL:                             /* DECLARE */
+case XXSORT:
+    return(hmsga(hxxdcl));
+
+case XXDEF:                             /* DEFINE */
+#ifndef NOSPL
+    if (hlptok)                         /* What they actually typed... */
+      if (hlptok[0] == '.')
+        return(hmsga(hxxdot));
+#endif /* NOSPL */
+    return(hmsga(hxxdef));
+
+case XXUNDEF:                           /* UNDEFINE */
+    return(hmsg("Syntax:  UNDEFINE variable-name\n\
+  Undefines a macro or variable."));
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+case XXLDEL:
+    return(hmsg(
+"  LDELETE is an alias for the DELETE command forcing it to execute\n\
+  on the local computer.  Also see: DELETE, RDELETE, SET LOCUS."));
+
+case XXDEL:                             /* delete */
+    return(hmsga(hmxxdel));
+#endif /* NOFRILLS */
+
+#ifndef NODIAL
+case XXDIAL:                            /* DIAL, etc... */
+    return(hmsga(hxxdial));
+
+case XXPDIA:                            /* PDIAL */
+    return(hmsg("Syntax: PDIAL phonenumber\n\
+  Partially dials a phone number.  Like DIAL but does not wait for carrier\n\
+  or CONNECT message."));
+
+case XXRED:
+    return(hmsg("Redial the number given in the most recent DIAL commnd."));
+
+case XXANSW:                            /* ANSWER */
+    return(hmsga(hxxansw));
+
+case XXLOOK:                            /* LOOKUP number in directory */
+    return(hmsga(hxxlook));
+#endif /* NODIAL */
+
+case XXLDIR:                            /* LDIRECTORY */
+    return(hmsg(
+"  LDIRIRECTORY is an alias for the DIRECTORY command forcing it to execute\n\
+  on the local computer.  Also see: DIRECTORY, SET LOCUS, RDIRECTORY."));
+
+case XXDIR:                             /* DIRECTORY */
+    return(hmsga(hmxxdir));
+
+case XXLMKD:                            /* LMKDIR */
+    return(hmsg(
+"  LMKDIR is an alias for the MKDIR command forcing it to execute\n\
+  on the local computer.  Also see: MKDIR, RMKDIR, SET LOCUS."));
+
+case XXMKDIR:                           /* MKDIR */
+    return(hmsg("Creates a directory.  Also see LRMDIR, RRMDIR, SET LOCUS."));
+
+case XXLRMD:                            /* LRMDIR */
+    return(hmsg(
+"  LRMDIR is an alias for the RMDIR command forcing it to execute\n\
+  on the local computer.  Also see: RMDIR, RRMDIR, SET LOCUS."));
+
+case XXRMDIR:                           /* RMDIR */
+    return(hmsg("Removes a directory.  Also see LRMDIR, RRMDIR, SET LOCUS."));
+
+case XXLS:
+#ifdef UNIXOROSK
+    return(hmsg("Syntax: LS [ args ]\n\
+  Runs \"ls\" with the given arguments."));
+#else
+    return(hmsga(hmxxdir));
+#endif /* UNIXOROSK */
+
+#ifndef NOSERVER
+#ifndef NOFRILLS
+case XXDIS:
+    return(hmsg("Syntax: DISABLE command\n\
+  Security for the Kermit server.  Prevents the client Kermit program from\n\
+  executing the named REMOTE command, such as CD, DELETE, RECEIVE, etc."));
+#endif /* NOFRILLS */
+#endif /* NOSERVER */
+
+#ifndef NOSPL
+case XXDO:                              /* do */
+    return(hmsg("Syntax: [ DO ] macroname [ arguments ]\n\
+  Executes a macro that was defined with the DEFINE command.  The word DO\n\
+  can be omitted.  Trailing argument words, if any, are automatically\n\
+  assigned to the macro argument variables \\%1 through \\%9."));
+#endif /* NOSPL */
+
+#ifndef NOSPL
+case XXDEC:
+    return(hmsga(hxxdec));
+#endif /* NOSPL */
+
+case XXECH:                             /* echo */
+    return(hmsg("Syntax: ECHO text\n\
+  Displays the text on the screen, followed by a line terminator.  The ECHO\n\
+  text may contain backslash codes.  Example: ECHO \\7Wake up!\\7.  Also see\n\
+  XECHO and WRITE SCREEN."));
+
+case XXXECH:                            /* xecho */
+    return(hmsg("Syntax: XECHO text\n\
+  Just like ECHO but does not add a line terminator to the text.  See ECHO."));
+
+case XXVOID:
+    return(hmsg("Syntax: VOID text\n\
+  Like ECHO but doesn't print anything; can be used to invoke functions\n\
+  when you don't need to display or use their results."));
+
+#ifndef NOSERVER
+#ifndef NOFRILLS
+case XXENA:
+    return(hmsg("Syntax: ENABLE capability\n\
+  For use with server mode.  Allows the client Kermit program access to the\n\
+  named capability, such as CD, DELETE, RECEIVE, etc.  Opposite of DISABLE."));
+#endif /* NOFRILLS */
+#endif /* NOSERVER */
+
+#ifndef NOSPL
+case XXEND:                             /* end */
+    return(hmsg("Syntax: END [ number [ message ] ]\n\
+  Exits from the current macro or TAKE file, back to wherever invoked from.\n\
+  Number is return code.  Message, if given, is printed."));
+
+case XXEVAL:                            /* evaluate */
+    return(hmsga(hmxxeval));
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+case XXERR:                             /* e-packet */
+    return(hmsg("Syntax: E-PACKET\n\
+  Sends an Error packet to the other Kermit."));
+#endif /* NOFRILLS */
+
+case XXEXI:                             /* exit */
+case XXQUI:
+    return(hmsga(hmxxexit));
+
+case XXFIN:
+    return(hmsg("Syntax: FINISH\n\
+  Tells the remote Kermit server to shut down without logging out."));
+
+#ifndef NOSPL
+  case XXFOR:
+    return(hmsga(forhlp));
+#endif /* NOSPL */
+
+  case XXGET:
+    return(hmsga(hmxxget));
+  case XXMGET:
+    return(hmsga(hmxxmget));
+
+#ifndef NOSPL
+#ifndef NOFRILLS
+  case XXGOK:
+    return(hmsg("Syntax: GETOK [ switches ] prompt\n\
+  Prints the prompt, makes user type 'yes', 'no', or 'ok', and sets SUCCESS\n\
+  or FAILURE accordingly.  The optional switches are the same as for ASK."));
+#endif /* NOFRILLS */
+#endif /* NOSPL */
+
+#ifndef NOSPL
+  case XXGOTO:
+    return(hmsg("Syntax: GOTO label\n\
+  In a TAKE file or macro, go to the given label.  A label is a word on the\n\
+  left margin that starts with a colon (:).  Example:\n\n\
+  :oofa\n\
+  echo Hello!\n\
+  goto oofa"));
+#endif /* NOSPL */
+
+  case XXHAN:
+    return(hmsg("Syntax: HANGUP\n\
+Hang up the phone or network connection."));
+
+  case XXHLP:
+/*
+  We get confirmation here, even though we do it again in hmsga(), to prevent
+  the Copyright message from being printed prematurely.  This doesn't do any
+  harm, because the first call to cmcfm() sets cmflgs to 1, making the second
+  call return immediately.
+*/
+    if ((x = cmcfm()) < 0)
+      return(x);
+
+    if (helpfile) {
+        printf("\n%s, Copyright (C) 1985, 2004,\n\
+Trustees of Columbia University in the City of New York.\n\n",versio);
+        return(dotype(helpfile,xaskmore,3,0,NULL,0,NULL,0,0,NULL,0));
+    } else {
+        printf("\n%s, Copyright (C) 1985, 2004,",versio);
+        return(hmsga(tophlp));
+    }
+
+case XXINT:
+#ifdef OS2
+    return(hmsg("Give a brief introduction to C-Kermit."));
+#else
+    return(hmsg("Give a brief introduction to Kermit 95."));
+#endif /* OS2 */
+
+#ifndef NOSPL
+case XXIF:
+    return(hmsga(ifhlp));
+
+case XXINC:
+    return(hmsga(hxxinc));
+
+case XXINP:
+   return(hmsga(hxxinp));
+#endif /* NOSPL */
+
+#ifdef CK_MINPUT
+case XXMINP:
+    return(hmsga(hmxxminp));
+#endif /* CK_MINPUT */
+
+#ifndef NOSPL
+case XXREI:
+    return(hmsg("Syntax: REINPUT n string\n\
+  Looks for the string in the text that has recently been INPUT, set SUCCESS\n\
+  or FAILURE accordingly.  Timeout, n, must be specified but is ignored."));
+#endif /* NOSPL */
+
+#ifndef NOSPL
+case XXLBL:
+    return(hmsg("\
+  Introduces a label, like :loop, for use with GOTO in TAKE files or macros.\n\
+See GOTO."));
+#endif /* NOSPL */
+
+case XXLOG:
+    return(hmsga(hmxxlg));
+
+#ifndef NOSCRIPT
+case XXLOGI:
+    return(hmsga(hmxxlogi));
+#endif
+
+#ifndef NOFRILLS
+case XXMAI:
+    return(hmsg("Syntax: MAIL filename address\n\
+  Equivalent to SEND /MAIL:address filename."));
+#endif /* NOFRILLS */
+
+#ifndef NOMSEND
+case XXMSE:
+    return(hmsga(hmxxmse));
+
+case XXADD:
+    return(hmsga(hmxxadd));
+
+case XXMMOVE:
+    return(hmsg("MMOVE is exactly like MSEND, except each file that is\n\
+sent successfully is deleted after it is sent."));
+#endif /* NOMSEND */
+
+#ifndef NOSPL
+case XXOPE:
+    return(hmsga(openhlp));
+#endif /* NOSPL */
+
+case XXNEW:
+    return(hmsg(
+"  Prints news of new features since publication of \"Using C-Kermit\"."));
+
+case XXUPD:
+    return(hmsg(
+"  New features are described in the online Kermit 95 manual,\n\
+   accessible via the MANUAL command."));
+
+#ifndef NOSPL
+case XXOUT:
+    return(hmsga(hxxout));
+#endif /* NOSPL */
+
+#ifdef ANYX25
+#ifndef IBMX25
+case XXPAD:
+    return(hmsga(hxxpad));
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifndef NOSPL
+case XXPAU:
+    return(hmsga(hxxpau));
+
+case XXMSL:
+    return(hmsga(hxxmsl));
+#endif /* NOSPL */
+
+#ifdef TCPSOCKET
+case XXPNG:
+    return(hmsg("Syntax: PING [ IP-hostname-or-number ]\n\
+  Checks if the given IP network host is reachable.  Default host is from\n\
+  most recent SET HOST or TELNET command.  Runs system PING program, if any.")
+           );
+
+case XXFTP:
+#ifdef SYSFTP
+    return(hmsg("Syntax: FTP [ IP-hostname-or-number ]\n\
+  Makes an FTP connection to the given IP host or, if no host specified, to\n\
+  the current host.  Uses the system's FTP program, if any."));
+#else
+#ifndef NOFTP
+    return(doftphlp());
+#endif /* NOFTP */
+#endif /* SYSFTP */
+#endif /* TCPSOCKET */
+
+#ifndef NOFRILLS
+case XXPRI:
+#ifdef UNIX
+    return(hmsg("Syntax: PRINT file [ options ]\n\
+  Prints the local file on a local printer with the given options.  Also see\n\
+  HELP SET PRINTER."));
+#else
+#ifdef VMS
+    return(hmsg("Syntax: PRINT file [ options ]\n\
+  Prints the local file on a local printer with the given options.  Also see\n\
+  HELP SET PRINTER."));
+#else
+    return(hmsg("Syntax: PRINT file\n\
+  Prints the local file on a local printer.  Also see HELP SET PRINTER."));
+#endif /* UNIX */
+#endif /* VMS */
+#endif /* NOFRILLS */
+
+case XXPWD:
+case XXLPWD:
+    return(hmsg("Syntax: PWD\n\
+Print the name of the current working directory."));
+
+#ifndef NOSPL
+case XXREA:
+    return(hmsg("Syntax: READ variablename\n\
+  Reads a line from the currently open READ or !READ file into the variable\n\
+  (see OPEN)."));
+#endif /* NOSPL */
+
+#ifndef NOXFER
+case XXREC:
+    return(hmsga(hmxxrc));
+
+case XXREM:
+    y = cmkey(remcmd,nrmt,"Remote command","",xxstring);
+    return(dohrmt(y));
+#endif /* NOXFER */
+
+#ifndef NOSPL
+case XXRET:
+    return(hmsg("Syntax: RETURN [ value ]\n\
+  Return from a macro.  An optional return value can be given for use with\n\
+  \\fexecute(macro), which allows macros to be used like functions."));
+#endif /* NOSPL */
+
+#ifndef NOXFER
+case XXSEN:
+    return(hmsga(hmxxsen));
+case XXMOVE:
+    return(hmsg("MOVE is exactly like SEND, except each file that is\n\
+sent successfully is deleted after it is sent."));
+#ifndef NORESEND
+case XXRSEN:
+    return(hmsg(hmxxrsen));
+case XXREGET:
+    return(hmsg(hmxxrget));
+case XXPSEN:
+    return(hmsg(hmxxpsen));
+#endif /* NORESEND */
+
+#ifndef NOSERVER
+case XXSER:
+    return(hmsg(hmxxser));
+#endif /* NOSERVER */
+#endif /* NOXFER */
+
+#ifndef NOJC
+case XXSUS:
+    return(hmsg("Syntax: SUSPEND or Z\n\
+  Suspends Kermit.  Continue Kermit with the appropriate system command,\n\
+  such as fg."));
+#endif /* NOJC */
+
+case XXSET:
+    y = cmkey(prmtab,nprm,"Parameter","",xxstring);
+    debug(F101,"HELP SET y","",y);
+    return(dohset(y));
+
+#ifndef NOPUSH
+case XXSHE:
+    if (nopush) {
+        if ((x = cmcfm()) < 0) return(x);
+        printf("Sorry, help not available for \"%s\"\n",cmdbuf);
+        break;
+    } else
+       return(hmsga(hxxshe));
+#ifdef CK_REDIR
+case XXFUN:
+    return(hmsg("Syntax: REDIRECT command\n\
+  Runs the given local command with its standard input and output redirected\n\
+  to the current SET LINE or SET HOST communications path.\n\
+  Synonym: < (Left angle bracket)."));
+#endif /* CK_REDIR */
+
+#ifdef CK_REXX
+case XXREXX:
+    return(hmsg("Syntax: REXX text\n\
+  The text is a Rexx command to be executed. The \\v(rexx) variable is set\n\
+  to the Rexx command's return value.\n\
+  To execute a rexx program file, use:  REXX call <filename>\n\
+  Rexx programs may call Kermit functions by placing the Kermit command\n\
+  in single quotes.  For instance:  'set parity none'."));
+#endif /* CK_REXX */
+#endif /* NOPUSH */
+
+#ifndef NOSHOW
+case XXSHO:
+    return(hmsg("\
+  Display current values of various items (SET parameters, variables, etc).\n\
+  Type SHOW ? for a list of categories."));
+#endif /* NOSHOW */
+
+case XXSPA:
+#ifdef datageneral
+    return(hmsg("\
+  Display disk usage in current device, directory,\n\
+  or return space for a specified device, directory."));
+#else
+    return(hmsg("Syntax: SPACE\n\
+  Display disk usage in current device and/or directory"));
+#endif
+
+case XXSTA:
+    return(hmsg("Syntax: STATISTICS [/BRIEF]\n\
+  Display statistics about most recent file transfer"));
+
+#ifndef NOSPL
+case XXSTO:
+    return(hmsg("Syntax: STOP [ number [ message ] ]\n\
+  Stop executing the current macro or TAKE file and return immediately to\n\
+  the Kermit prompt.  Number is a return code.  Message printed if given."));
+#endif /* NOSPL */
+
+case XXTAK:
+    return(hmsga(hmxxtak));
+
+#ifdef TCPSOCKET
+#ifdef TNCODE
+case XXIKSD:
+    return(hmsga(hmxxiks));
+
+case XXTEL:
+    return(hmsga(hmxxtel));
+
+case XXTELOP:
+    return(hmsga(hxtopt));
+#endif /* TNCODE */
+
+#ifdef RLOGCODE
+case XXRLOG:
+    return(hmsg("Syntax: RLOGIN [ switches ] [ host [ username ] ]\n\
+  Equivalent to SET NETWORK TYPE TCP/IP, SET HOST host [ service ] /RLOGIN,\n\
+  IF SUCCESS CONNECT.  If host is omitted, the previous connection (if any)\n\
+  is resumed.  Depending on how Kermit has been built switches may be\n\
+  available to require Kerberos authentication and DES encryption."));
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+
+#ifndef NOXMIT
+case XXTRA:
+    return(hmsga(hxxxmit));
+#endif /* NOXMIT */
+
+#ifndef NOFRILLS
+case XXTYP:
+    return(hmsga(hmxxtyp));
+case XXMORE:
+    return(hmsg("Syntax: MORE [ switches ] filename\n\
+  Equivalent to TYPE /PAGE filename; see HELP TYPE."));
+case XXCAT:
+    return(hmsg("Syntax: MORE [ switches ] filename\n\
+  Equivalent to TYPE /NOPAGE filename; see HELP TYPE."));
+case XXHEAD:
+    return(hmsg("Syntax: HEAD [ switches ] filename\n\
+  Equivalent to TYPE /HEAD filename; see HELP TYPE."));
+case XXTAIL:
+    return(hmsg("Syntax: TAIL [ switches ] filename\n\
+  Equivalent to TYPE /TAIL filename; see HELP TYPE."));
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+case XXWHI:
+    return(hmsga(whihlp));
+
+case XXSWIT:
+    return(hmsga(swihlp));
+#endif /* NOSPL */
+
+#ifndef NOCSETS
+case XXXLA:
+    return(hmsga(hxxxla));
+#endif /* NOCSETS */
+
+case XXVER:
+    return(hmsg("Syntax: VERSION\nDisplays the program version number."));
+
+#ifndef NOSPL
+case XXWAI:
+    return(hmsga(hxxwai));
+#endif /* NOSPL */
+
+#ifndef NOFRILLS
+case XXWHO:
+    return(hmsg("Syntax: WHO [ user ]\nDisplays info about the user."));
+
+case XXWRI:
+    return(hmsga(hxxwri));
+
+case XXWRL:
+    return(hmsg(
+"WRITE-LINE (WRITELN) is just like WRITE, but includes a line terminator\n\
+at the end of text.  See WRITE."));
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+case XXIFX:
+    return(hmsga(ifxhlp));
+
+case XXGETC:                            /* GETC */
+    return(hmsga(hxxgetc));
+
+case XXFWD:                             /* FORWARD */
+    return(hmsg(
+"Like GOTO, but searches only forward for the label.  See GOTO."));
+
+case XXLOCAL:                           /* LOCAL */
+    return(hmsg(
+"Declares a variable to be local to the current macro or command file."));
+#endif /* NOSPL */
+
+case XXVIEW:
+    return(hmsg(
+"View the terminal emulation screen even when there is no connection."));
+
+case XXASC:
+    return(hmsg("Synonym for SET FILE TYPE TEXT."));
+
+case XXBIN:
+    return(hmsg("Synonym for SET FILE TYPE BINARY."));
+
+case XXDATE:
+    return(hmsga(hmxxdate));
+
+case XXRETR:
+    return(hmsg(
+"Just like GET but asks the server to delete each file that has been\n\
+sent successfully."));
+
+case XXEIGHT:
+    return(hmsg(
+"Equivalent to SET PARITY NONE, SET COMMAND BYTE 8, SET TERMINAL BYTE 8."));
+
+case XXSAVE:
+    return(hmsga(hmxxsave));
+
+#ifndef NOFRILLS
+#ifndef NOPUSH
+case XXEDIT:
+    return(hmsg("Syntax: EDIT [ <file> ]\n\
+Starts your preferred editor on the given file, or if none given, the most\n\
+recently edited file, if any.  Also see SET EDITOR."));
+#endif /* NOPUSH */
+#endif /* NOFRILLS */
+
+#ifdef BROWSER
+case XXBROWS:
+    return(hmsg("Syntax: BROWSE [ <url> ]\n\
+Starts your preferred Web browser on the given URL, or if none given, the\n\
+most recently visited URL, if any.  Also see SET BROWSER."));
+#endif /* BROWSER */
+
+#ifdef CK_TAPI
+case XXTAPI:
+    return(hmsga(hxxtapi));
+#endif /* CK_TAPI */
+
+#ifdef PIPESEND
+case XXCSEN:
+    return(hmsg("Syntax: CSEND [ switches ] <command> [ <as-name> ]\n\
+Sends from the given <command> rather than from a file.  Equivalent to\n\
+SEND /COMMAND; see HELP SEND for details."));
+
+case XXCREC:
+    return(hmsg("Syntax: CRECEIVE [ switches ] <command>\n\
+Receives to the given <command> rather than to a file.  Equivalent to\n\
+RECEIVE /COMMAND; see HELP RECEIVE for details."));
+
+case XXCGET:
+    return(hmsg("Syntax: CGET <remote-file-or-command> <local-command>\n\
+Equivalent to GET /COMMAND; see HELP GET for details."));
+#endif /* PIPESEND */
+
+#ifndef NOSPL
+case XXFUNC:
+/*
+  Tricky parsing.  We want to let them type the function name in any format
+  at all: \fblah(), \fblah, \\fblah(), fblah, blah, blah(), etc, but of course
+  only one of these is recognized by cmkey().  So we call cmkeyx() (the "no
+  complaints" version of cmkey()), and if it fails, we try the other formats
+  silently, and still allow for <no-name-given>, editing and reparse, etc.
+*/
+    y = cmkeyx(fnctab,nfuncs,"Name of function","",NULL);
+    if (y == -1) {                      /* Reparse needed */
+        return(y);
+    } else if (y == -3) {
+        if ((x = cmcfm()) < 0)          /* For recall buffer... */
+          return(x);
+        return(dohfunc(y));             /* -3 gives general message */
+    }
+    if (y < 0) {                        /* Something given but didn't match */
+        int dummy;
+        char * p;
+        for (p = atmbuf; *p; p++) {     /* Chop off trailing parens if any */
+            if (*p == '(') {
+                *p = NUL;
+                break;
+            }
+        }
+        /* Chop off leading "\\f" or "\f" or "f" */
+        p = atmbuf;
+        if (*p == CMDQ)                 /* Allow for \\f... */
+          p++;
+        if (*p == CMDQ && (*(p+1) == 'f' || *(p+1) == 'F')) { /* or \f */
+            p += 2;
+        } else if (*p == 'f' || *p == 'F') { /* or just f */
+            p++;
+        }
+        y = lookup(fnctab,p,nfuncs,&dummy); /* Look up the result */
+    }
+    if (y < 0) {
+        printf("?No such function - \"%s\"\n",atmbuf);
+        return(-9);
+    }
+    x = cmgbrk();                       /* Find out how user terminated */
+    if (x == LF || x == CR)             /* if with CR or LF */
+      cmflgs = 1;                       /* restore cmflgs to say so */
+    if ((x = cmcfm()) < 0)              /* And THEN confirm so command will */
+      return(x);                        /* get into recall buffer. */
+    return(dohfunc(y));
+#endif /* NOSPL */
+
+#ifndef NOCMDL
+case XXOPTS:                            /* Command-line options */
+    return(dohopts());
+
+case XXXOPTS:                           /* Extended command-line options */
+    return(doxopts());
+#endif /* NOCMDL */
+
+#ifdef OS2
+#ifndef NOKVERBS
+case XXKVRB: {
+    y = cmkeyx(kverbs,nkverbs,"Name of keyboard verb without \\k","",NULL);
+    if (y == -1) {                      /* Reparse needed */
+        return(y);
+    } else if (y == -3) {
+        if ((x = cmcfm()) < 0)          /* For recall buffer... */
+          return(x);
+        return(dohkverb(y));            /* -3 gives general message */
+    }
+    if (y < 0) {                        /* Something given but didn't match */
+        int dummy;
+        char * p;
+        for (p = atmbuf; *p; p++) {     /* Chop off trailing parens if any */
+            if (*p == '(') {
+                *p = NUL;
+                break;
+            }
+        }
+        /* Chop off leading "\\k" or "\k" or "k" */
+        p = atmbuf;
+        if (*p == CMDQ)                 /* Allow for \\k... */
+          p++;
+        if (*p == CMDQ && (*(p+1) == 'k' || *(p+1) == 'K')) { /* or \k */
+            p += 2;
+        } else if (*p == 'k' || *p == 'K') { /* or just k */
+            p++;
+        }
+        y = lookup(kverbs,p,nkverbs,&dummy); /* Look up the result */
+    }
+    if (y < 0) {
+        printf("?No such function - \"%s\"\n",atmbuf);
+        return(-9);
+    }
+    x = cmgbrk();                       /* Find out how user terminated */
+    if (x == LF || x == CR)             /* if with CR or LF */
+      cmflgs = 1;                       /* restore cmflgs to say so */
+    if ((x = cmcfm()) < 0)              /* And THEN confirm so command will */
+      return(x);                        /* get into recall buffer. */
+    return(dohkverb(y));
+}
+#endif /* NOKVERBS */
+#endif /* OS2 */
+
+case XXKERMI:
+    return(hmsg("Syntax: KERMIT [command-line-options]\n\
+  Lets you give command-line options at the prompt or in a script.\n\
+  HELP OPTIONS for more info."));
+
+case XXBACK:
+    return(hmsg("Syntax: BACK\n  Returns to your previous directory."));
+
+case XXWHERE:
+    return(hmsg("Syntax: WHERE\n  Tells where your transferred files went."));
+
+#ifndef NOXFER
+case XXREMV:
+    return(hmsga(hmxxremv));
+#endif /* NOXFER */
+
+#ifdef CK_KERBEROS
+case XXAUTH:
+    return(hmsga(hmxxauth));
+#endif /* CK_KERBEROS */
+
+#ifndef NOHTTP
+case XXHTTP:
+    return(hmsga(hmxxhttp));
+#endif /* NOHTTP */
+
+#ifdef NETCMD
+case XXPIPE:
+    return(hmsg("Syntax: PIPE [ command ]\n\
+Makes a connection through the program whose command line is given. Example:\n\
+\n pipe rlogin xyzcorp.com"));
+#endif /* NETCMD */
+
+case XXSTATUS:
+    return(hmsg(
+"STATUS is the same as SHOW STATUS; prints SUCCESS or FAILURE for the\n\
+previous command."));
+
+#ifndef NOSPL
+case XXASSER:
+    return(hmsg("Syntax: ASSERT <condition>\n\
+Succeeds or fails depending on <condition>; see HELP IF for <condition>s."));
+
+case XXFAIL:
+    return(hmsg("Always fails."));
+
+case XXSUCC:
+    return(hmsg("Always succeeds."));
+#endif /* NOSPL */
+
+#ifdef CK_LOGIN
+case XXLOGOUT:
+    return(hmsg(
+"If you haved logged in to Kermit as an Internet Kermit server, the LOGOUT\n\
+command, given at the prompt, logs you out and closes your session."));
+#endif /* CK_LOGIN */
+
+case XXRESET:
+    return(hmsg("Closes all open files and logs."));
+
+#ifndef NOCSETS
+case XXASSOC:
+    return(hmsga(hmxxassoc));
+#endif /* NOCSETS */
+
+#ifndef NOSPL
+case XXSHIFT:
+    return(hmsg("Syntax: SHIFT [ n ]\n\
+  Shifts \\%1..9 variables n places to the left; default n = 1."));
+#endif /* NOSPL */
+
+#ifndef NOPUSH
+case XXMAN:
+#ifdef UNIX
+    return(hmsg("Syntax: MANUAL [ topic ]\n\
+  Runs the \"man\" command on the given topic (default \"kermit\")."));
+#else
+#ifdef OS2
+    return(hmsg("Syntax: MANUAL\n\
+  Accesses the Kermit 95 HTML manual using the current browser."));
+#else
+    return(hmsg("Syntax: MANUAL [ topic ]\n\
+  Runs the \"help\" command on the given topic (default \"kermit\")."));
+#endif /* OS2 */
+#endif /* UNIX */
+#endif /* NOPUSH */
+
+case XXWILD:
+    return(hmsga(hmxxwild));
+
+case XXPAT:
+    return(hmsga(hmxxpat));
+
+#ifndef NOXFER
+case XXFAST:
+case XXCAU:
+case XXROB:
+    return(hmsga(hmxxfast));
+#endif /* NOXFER */
+
+#ifdef CKPURGE
+case XXPURGE:
+    return(hmsga(hmxxpurge));
+#else
+#ifdef VMS
+case XXPURGE:
+    return(hmsga(hmxxpurge));
+#endif /* VMS */
+#endif /* CKPURGE */
+
+#ifndef NOXFER
+  case XXRASG:
+    return(hmsg("  RASG and RASSIGN are short forms of REMOTE ASSIGN."));
+  case XXRCWD:
+    return(hmsg("  RCD and RCWD are short forms of REMOTE CD."));
+  case XXRCPY:
+    return(hmsg("  RCOPY is a short form of REMOTE COPY."));
+  case XXRDEL:
+    return(hmsg("  RDELETE is a short form of REMOTE RELETE."));
+  case XXRDIR:
+    return(hmsg("  RDIRECTORY is a short form of REMOTE DIRECTORY."));
+  case XXRXIT:
+    return(hmsg("  REXIT is a short form of REMOTE EXIT."));
+  case XXRHLP:
+    return(hmsg("  RHELP is a short form of REMOTE HELP."));
+  case XXRHOS:
+    return(hmsg("  RHOST is a short form of REMOTE HOST."));
+  case XXRKER:
+    return(hmsg("  RKERMIT is a short form of REMOTE KERMIT."));
+  case XXRMKD:
+    return(hmsg("  RMKDIR is a short form of REMOTE MKDIR."));
+  case XXRPRI:
+    return(hmsg("  RPRINT is a short form of REMOTE PRINT."));
+  case XXRPWD:
+    return(hmsg("  RPWD is a short form of REMOTE PWD."));
+  case XXRQUE:
+    return(hmsg("  QUERY and RQUERY are short forms of REMOTE QUERY."));
+  case XXRREN:
+    return(hmsg("  RRENAME is a short form of REMOTE RENAME."));
+  case XXRRMD:
+    return(hmsg("  RRMDIR is a short form of REMOTE RMDIR."));
+  case XXRSET:
+    return(hmsg("  RSET is a short form of REMOTE SET."));
+  case XXRSPA:
+    return(hmsg("  RSPACE is a short form of REMOTE SPACE."));
+  case XXRTYP:
+    return(hmsg("  RTYPE is a short form of REMOTE TYPE."));
+  case XXRWHO:
+    return(hmsg("  RWHO is a short form of REMOTE WHO."));
+#endif /* NOXFER */
+
+  case XXSCRN:
+    return(hmsga(hmxxscrn));
+
+#ifdef CKEXEC
+  case XXEXEC:
+    return(hmsg("Syntax: EXEC <command> [ <arg1> [ <arg2> [ ... ] ]\n\
+  C-Kermit overlays itself with the given system command and starts it with\n\
+  the given arguments.  Upon any error, control returns to C-Kermit."));
+#endif /* CKEXEC */
+
+#ifndef NOSPL
+  case XXTRACE:
+    return(hmsg(
+"Syntax: TRACE { /ON, /OFF } { ASSIGNMENTS, COMMAND-LEVEL, ALL }\n\
+  Turns tracing of the given object on or off."));
+#endif /* NOSPL */
+
+#ifdef CK_PERMS
+#ifdef UNIX
+  case XXCHMOD:
+    return(hmsga(hmxxchmod));
+#endif /* UNIX */
+#endif /* CK_PERMS */
+
+#ifdef CKROOT
+  case XXCHRT:
+    return(hmsga(hmxxchroot));
+#endif /* CKROOT */
+
+#ifndef NOSPL
+  case XXPROMP:
+    return(hmsga(hmxxprompt));
+#endif /* NOSPL */
+
+  case XXGREP:
+    return(hmsga(hmxxgrep));
+
+#ifndef NOSEXP
+#ifndef NOSPL
+  case XXSEXP:
+    return(hmsga(hmxxsexp));
+#endif /* NOSPL */
+#endif /* NOSEXP */
+
+#ifdef CKLEARN
+  case XXLEARN:
+    return(hmsga(hmxxlearn));
+#endif /* CKLEARN */
+
+#ifdef ANYSSH
+  case XXSSH:
+    return(hmsga(hmxxssh));
+#endif /* ANYSSH */
+
+#ifdef TCPSOCKET
+  case XXFIREW:
+    return(hmsga(hmxxfirew));
+#endif /* TCPSOCKET */
+
+#ifdef NEWFTP
+  case XXUSER:
+    return(hmsg(" Equivalent to FTP USER."));
+  case XXACCT:
+    return(hmsg(" Equivalent to FTP ACCOUNT."));
+#endif /* NEWFTP */
+
+  case XXORIE:
+    return(hmsg(" Shows the directories important to Kermit."));
+
+  case XXCONT:
+    return(hmsg(" In a FOR or WHILE loop: continue the loop.\n\
+ At the prompt: continue a script that has \"shelled out\" to the prompt."));
+
+  case XXNOTAV:
+    return(hmsg(" This command is not configured in this version of Kermit."));
+
+default: {
+        char *s;
+        if ((x = cmcfm()) < 0) return(x);
+        s = cmdbuf + (int)strlen(cmdbuf) -1;
+        while (s >= cmdbuf && *s == SP)
+          *s-- = NUL;
+        while (s >= cmdbuf && *s != SP)
+          s--;
+        while (*s == SP) s++;
+        printf("Sorry, help not available for \"%s\"\n",s);
+        break;
+      }
+    } /* switch */
+#endif /* NOHELP */
+
+    return(success = 0);
+}
+
+/*  H M S G  --  Get confirmation, then print the given message  */
+
+int
+hmsg(s) char *s; {
+    int x;
+    if ((x = cmcfm()) < 0) return(x);
+    printf("\n%s\n\n",s);
+    return(0);
+}
+
+#ifdef NOHELP
+
+int                                     /* Print an array of lines, */
+hmsga(s) char *s[]; {                   /* cheap version. */
+    int i;
+    if ((i = cmcfm()) < 0) return(i);
+    printf("\n");                       /* Start off with a blank line */
+    for (i = 0; *s[i]; i++) {           /* Print each line. */
+        printf("%s\n",s[i]);
+    }
+    printf("\n");
+    return(0);
+}
+
+#else /* NOHELP not defined... */
+
+int                                     /* Print an array of lines, */
+hmsga(s) char *s[]; {                   /* pausing at end of each screen. */
+    extern int hmtopline;               /* (This should be a parameter...) */
+    int x, y, i, j, k, n;
+    if ((x = cmcfm()) < 0) return(x);
+
+#ifdef CK_TTGWSIZ
+#ifdef OS2
+    ttgcwsz();
+#else /* OS2 */
+    /* Check whether window size changed */
+    if (ttgwsiz() > 0) {
+        if (tt_rows > 0 && tt_cols > 0) {
+            cmd_rows = tt_rows;
+            cmd_cols = tt_cols;
+        }
+    }
+#endif /* OS2 */
+#endif /* CK_TTGWSIZ */
+
+    printf("\n");                       /* Start off with a blank line */
+    n = (hmtopline > 0) ? hmtopline : 1; /* Line counter */
+    for (i = 0; *s[i]; i++) {
+        printf("%s\n",s[i]);            /* Print a line. */
+        y = (int)strlen(s[i]);
+        k = 1;
+        for (j = 0; j < y; j++)         /* See how many newlines were */
+          if (s[i][j] == '\n') k++;     /* in the string... */
+        n += k;
+        if (n > (cmd_rows - 3) && *s[i+1]) /* After a screenful, give them */
+          if (!askmore()) return(0);    /* a "more?" prompt. */
+          else n = 0;
+    }
+    printf("\n");
+    return(0);
+}
+
+#ifndef NOXMIT
+static char *hsetxmit[] = {
+"Syntax: SET TRANSMIT parameter value",
+" ",
+"Controls the behavior of the TRANSMIT command (see HELP TRANSMIT):",
+" ",
+"SET TRANSMIT ECHO { ON, OFF }",
+"  Whether to echo text to your screen as it is being transmitted.",
+" ",
+"SET TRANSMIT EOF text",
+"  Text to send after end of file is reached, e.g. \\4 for Ctrl-D",
+" ",
+"SET TRANSMIT FILL number",
+"  ASCII value of a character to insert into blank lines, 0 for none.",
+"  Applies only to text mode.  0 by default.",
+" ",
+"SET TRANSMIT LINEFEED { ON, OFF }",
+"  Transmit Linefeed as well as Carriage Return (CR) at the end of each line.",
+"  Normally, only CR  is sent.",
+" ",
+"SET TRANSMIT LOCKING-SHIFT { ON, OFF }",
+"  Whether to use SO/SI for transmitting 8-bit data when PARITY is not NONE.",
+" ",
+"SET TRANSMIT PAUSE number",
+"  How many milliseconds to pause after transmitting each line (text mode),",
+"  or each character (binary mode).",
+" ",
+"SET TRANSMIT PROMPT number",
+"  ASCII value of character to look for from host before sending next line",
+"  when TRANSMITting in text mode; normally 10 (Linefeed).  0 means none;",
+"  don't wait for a prompt.",
+" ",
+"SET TRANSMIT TIMEOUT number",
+"  Number of seconds to wait for each character to echo when TRANSMIT ECHO",
+"  is ON or TRANSMIT PROMPT is not 0.  If 0 is specified, this means wait",
+"  indefinitely for each echo.",
+" ",
+"Synonym: SET XMIT.  SHOW TRANSMIT displays current settings.",
+"" };
+#endif /* NOXMIT */
+
+static char *hsetbkg[] = {
+"Syntax: SET BACKGROUND { OFF, ON }",
+" ",
+"  SET BACKGROUND OFF forces prompts and messages to appear on your screen",
+"  even though Kermit thinks it is running in the background.",
+"" };
+
+#ifdef DYNAMIC
+static char *hsetbuf[] = {
+"Syntax: SET BUFFERS n1 [ n2 ]",
+" ",
+"  Changes the overall amount of memory allocated for SEND and RECEIVE packet",
+"  buffers, respectively.  Bigger numbers let you have longer packets and",
+"  more window slots.  If n2 is omitted, the same value as n1 is used.",
+#ifdef BIGBUFOK
+" ",
+"  NOTE: This command is not needed in this version of Kermit, which is",
+"  already configured for maximum-size packet buffers.",
+#endif /* BIGBUFOK */
+"" };
+#endif /* DYNAMIC */
+
+static char *hsetcmd[] = {
+"Syntax: SET COMMAND parameter value",
+" ",
+
+#ifdef CK_AUTODL
+"SET COMMAND AUTODOWNLOAD { ON, OFF }",
+"  Enables/Disables automatic recognition of Kermit packets while in",
+"  command mode.  ON by default.",
+" ",
+#endif /* CK_AUTODL */
+
+"SET COMMAND BYTESIZE { 7, 8 }",
+"  Informs Kermit of the bytesize of the communication path between itself",
+"  and your keyboard and screen.  8 is assumed.  SET COMMAND BYTE 7 only if",
+"  8-bit characters cannot pass.",
+" ",
+
+#ifdef OS2
+"SET COMMAND COLOR <foreground-color> <background-color>",
+"  Lets you choose colors for Command screen.  Use ? in the color fields to",
+"  to get lists of available colors.",
+" ",
+"SET COMMAND CURSOR-POSITION <row> <column>",
+"  Moves the command-screen cursor to the given position (1-based).  This",
+"  command should be used in scripts instead of relying on ANSI.SYS escape",
+"  sequences.",
+" ",
+#endif /* OS2 */
+
+#ifdef OS2
+#ifdef NT
+"SET COMMAND HEIGHT <number>",
+"  Changes the number of rows (lines) in your command screen, not",
+"  counting the status line.  Recommended values are 24, 42, and 49 (or 25,",
+"  43, and 50 if SET COMMAND STATUSLINE is OFF.)",
+#else
+"SET COMMAND HEIGHT <number>"
+"  Changes the number of rows (lines) in your command screen, not",
+"  counting the status line.  Windowed sessions can use any value from 8 to",
+"  101.  Fullscreen sessions are limited to 24, 42, 49, or 59.  Not all"
+"  heights are supported by all video adapters.",
+#endif /* NT */
+#else  /* OS2 */
+"SET COMMAND HEIGHT <number>",
+"  Informs Kermit of the number of rows in your command screen for the",
+"  purposes of More?-prompting.",
+#endif /* OS2 */
+" ",
+"SET COMMAND WIDTH <number>",
+"  Informs Kermit of the number of characters across your screen for",
+"  purposes of screen formatting.",
+" ",
+"SET COMMAND MORE-PROMPTING { ON, OFF }",
+"  ON (the default) enables More?-prompting when Kermit needs to display",
+"  text that does not fit vertically on your screen.  OFF allows the text to",
+"  scroll by without intervention.  If your command window has scroll bars,",
+"  you might prefer OFF.",
+" ",
+
+#ifdef CK_RECALL
+"SET COMMAND RECALL-BUFFER-SIZE number",
+"  How big you want Kermit's command recall buffer to be.  By default, it",
+"  holds 10 commands.  You can make it any size you like, subject to memory",
+"  constraints of the computer.  A size of 0 disables command recall.",
+"  Whenever you give this command, previous command history is lost.",
+" ",
+#endif /* CK_RECALL */
+
+"SET COMMAND QUOTING { ON, OFF }",
+"  Whether to treat backslash and question mark as special characters (ON),",
+"  or as ordinary data characters (OFF) in commands.  ON by default.",
+" ",
+#ifdef DOUBLEQUOTING
+"SET COMMAND DOUBLEQUOTING { ON, OFF }",
+"  Whether to allow doublequotes (\") to be used to enclose fields,",
+"  filenames, directory names, and macro arguments that might contain",
+"  spaces.  ON by default; use OFF to force compatibility with older",
+"  versions.",
+" ",
+#endif /* DOUBLEQUOTING */
+
+#ifdef CK_RECALL
+"SET COMMAND RETRY { ON, OFF }",
+"  Whether to reprompt you with the correct but incomplete portion of a",
+"  syntactically incorrect command.  ON by default.",
+" ",
+#endif /* CK_RECALL */
+
+#ifdef OS2
+"SET COMMAND SCROLLBACK <lines>",
+"  Sets size of virtual Command screen buffer to the given number of lines,",
+"  which includes the active Command screen.  The minimum is 256.  The max",
+"  is 2 million.  The default is 512.",
+" ",
+"SET COMMAND STATUSLINE { ON, OFF }",
+"  ON (default) enables the Kermit status line in the command screen.",
+"  OFF removes it, making the line available for use by the host.",
+" ",
+#endif /* OS2 */
+
+"Use SHOW COMMAND to display these settings.",
+"" };
+
+#ifndef NOLOCAL
+static char *hsetcar[] = {
+"Syntax: SET CARRIER-WATCH { AUTO, OFF, ON }",
+" ",
+"  Attempts to control treatment of carrier (the Data Carrier Detect signal)",
+"  on serial communication (SET LINE or SET PORT) devices.  ON means that",
+"  carrier is required at all times.  OFF means carrier is never required.",
+"  AUTO (the default) means carrier is required at all times except during",
+"  the DIAL command.  Correct operation of carrier-watch depends on the",
+"  capabilities of the underlying OS, drivers, devices, and cables.  If you",
+"  need to CONNECT to a serial device that is not asserting carrier, and",
+"  Kermit won't let you, use SET CARRIER-WATCH OFF.  Use SHOW COMMUNICATIONS",
+"  to display the CARRIER-WATCH setting.",
+"" };
+#endif /* NOLOCAL */
+
+static char *hsetat[] = {
+"Syntax: SET ATTRIBUTES name ON or OFF",
+" ",
+"  Use this command to enable (ON) or disable (OFF) the transmission of",
+"  selected file attributes along with each file, and to handle or ignore",
+"  selected incoming file attributes, including:",
+" ",
+#ifndef NOCSETS
+"   CHARACTER-SET:  The transfer character set for text files",
+#endif /* NOCSETS */
+"   DATE:           The file's creation date",
+"   DISPOSITION:    Unusual things to do with the file, like MAIL or PRINT",
+"   LENGTH:         The file's length",
+"   PROTECTION:     The file's protection (permissions)",
+"   SYSTEM-ID:      Machine/Operating system of origin",
+"   TYPE:           The file's type (text or binary)",
+" ",
+"You can also specify ALL to select all of them.  Examples:",
+" ",
+"   SET ATTR DATE OFF",
+"   SET ATTR LENGTH ON",
+"   SET ATTR ALL OFF",
+" ",
+"Also see HELP SET SEND and HELP SET RECEIVE.",
+""
+};
+
+static char *hxytak[] = {
+"Syntax: SET TAKE parameter value",
+" ",
+"  Controls behavior of TAKE command:",
+" ",
+"SET TAKE ECHO { ON, OFF }",
+"  Tells whether commands read from a TAKE file should be displayed on the",
+"  screen (if so, each command is shown at the time it is read, and labeled",
+"  with a line number).",
+" ",
+"SET TAKE ERROR { ON, OFF }",
+"  Tells whether a TAKE command file should be automatically terminated when",
+"  a command fails.  This setting is local to the current command file, and",
+"  inherited by subordinate command files.",
+"" };
+
+#ifndef NOLOCAL
+#ifdef OS2MOUSE
+static char *hxymouse[] = {
+"Syntax: SET MOUSE ACTIVATE { ON, OFF }",
+"  Enables or disables the mouse in Connect mode.  Default is ON",
+" ",
+"Syntax: SET MOUSE BUTTON <number> <key-modifier> <action> [ <text> ]",
+" where:",
+"  <number> is the mouse button number, 1, 2, or 3;",
+"  <key-modifier> denotes modifier keys held down during the mouse event:",
+"   ALT, ALT-SHIFT, CTRL, CTRL-ALT CTRL-ALT-SHIFT, CTRL-SHIFT, SHIFT, NONE;",
+"  <action> is the mouse action, CLICK, DRAG, or DOUBLE-CLICK.",
+" ",
+" The <text> has exactly the same properties as the <text> from the SET KEY",
+" command -- it can be a character, a string, one or more Kverbs, a macro",
+" invoked as a Kverb, or any combination of these.  Thus, anything that can",
+" be assigned to a key can also be assigned to the mouse -- and vice versa.",
+" If the <text> is omitted, the action will be ignored.  Examples:",
+" ",
+" SET MOUSE BUTTON 1 NONE DOUBLE \\KmouseCurPos",
+" SET MOU B 2 SHIFT CLICK help\\13",
+" ",
+" DRAG operations perform a \"mark mode\" selection of Text. You should",
+" assign only the following actions to drag operations:",
+" ",
+"  \\Kdump         - copy marked text to printer (or file)",
+"  \\Kmarkcopyclip - copy marked text to PM Clipboard",
+"  \\Kmarkcopyhost - copy marked text direct to Host",
+"  \\Kmousemark    - mark text, no copy operation performed",
+" ",
+" The following Kverb is only for use with the mouse:",
+" ",
+"  \\KmouseCurPos",
+" ",
+" which represents the mouse-directed terminal cursor feature.",
+" ",
+"Syntax: SET MOUSE CLEAR",
+" Restores all mouse events to their default definitions",
+"   Button 1 Ctrl-Click = Kverb: \\Kmouseurl",
+"   Button 1 Double-Click = Kverb: \\Kmousecurpos",
+"   Button 1 Drag = Kverb: \\Kmarkcopyclip",
+"   Button 1 Alt-Drag = Kverb: \\Kmarkcopyclip_noeol",
+"   Button 1 Ctrl-Drag = Kverb: \\Kmarkcopyhost",
+"   Button 1 Ctrl-Alt-Drag = Kverb: \\Kmarkcopyhost_noeol",
+"   Button 1 Ctrl-Shift-Drag = Kverb: \\Kdump",
+"   Button 2 Double-Click = Kverb: \\Kpaste",
+"   Button 2 Drag = Kverb: \\Kmarkcopyhost",
+"   Button 2 Alt-Drag = Kverb: \\Kmarkcopyhost_noeol     ",    
+"   Button 3 Double-Click = Kverb: \\Kpaste",
+""};
+#endif /* OS2MOUSE */
+
+static char *hxyterm[] = {
+"Syntax: SET TERMINAL parameter value",
+" ",
+#ifdef OS2
+"SET TERMINAL TYPE { ANSI, VT52, VT100, VT102, VT220, VT320, ... }",
+"  Selects type type of terminal to emulate.  Type SET TERMINAL TYPE ? to",
+"  see a complete list.",
+" ",
+"SET TERMINAL ANSWERBACK { OFF, ON }",
+"  Disables/enables the ENQ/Answerback sequence (\"K-95 version term-type\").",
+" ",
+"SET TERMINAL ANSWERBACK MESSAGE <extension>",
+"  Allows you to specify an extension to the default answerback message.",
+" ",
+#else
+"SET TERMINAL TYPE ...",
+"  This command is not available because this version of Kermit does not",
+"  include a terminal emulator.  Instead, it is a \"semitransparent pipe\"",
+"  (or a totally transparent one, if you configure it that way) to the",
+"  computer or service you have made a connection to.  Your console,",
+"  workstation window, or the terminal emulator or terminal from which you",
+"  are running Kermit provides the emulation.",
+" ",
+#endif /* OS2 */
+
+#ifdef CK_APC
+"SET TERMINAL APC { ON, OFF, NO-INPUT, NO-INPUT-UNCHECKED, UNCHECKED }",
+#ifdef OS2
+"  Controls execution of Application Program Commands sent by the host while",
+"  K-95 is either in CONNECT mode or processing INPUT commands.  ON allows",
+"  execution of \"safe\" commands and disallows potentially dangerous ones",
+"  such as DELETE, RENAME, OUTPUT, and RUN.  OFF prevents execution of APCs.",
+"  UNCHECKED allows execution of all APCs.  OFF is the default.",
+#else /* OS2 */
+"  Controls execution of Application Program Commands sent by the host while",
+"  C-Kermit is in CONNECT mode.  ON allows execution of \"safe\" commands and",
+"  disallows potentially dangerous commands such as DELETE, RENAME, OUTPUT,",
+"  and RUN.  OFF prevents execution of APCs.  UNCHECKED allows execution of",
+"  all APCs.  OFF is the default.",
+#endif /* OS2 */
+" ",
+#endif /* CK_APC */
+
+#ifdef OS2
+"SET TERMINAL ARROW-KEYS { APPLICATION, CURSOR }",
+"  Sets the mode for the arrow keys during VT terminal emulation.",
+" ",
+"SET TERMINAL ATTRIBUTE { BLINK, DIM, PROTECTED, REVERSE, UNDERLINE }",
+"  Determines how attributes are displayed by Kermit-95.",
+" ",
+"SET TERMINAL ATTRIBUTE { BLINK, DIM, REVERSE, UNDERLINE } { ON, OFF }",
+"  Determines whether real Blinking, Dim, Reverse, and Underline are used in",
+"  the terminal display.  When BLINK is turned OFF, reverse background",
+"  intensity is used.  When DIM is turned OFF, dim characters appear BOLD.",
+"  When REVERSE and UNDERLINE are OFF, the colors selected with SET",
+"  TERMINAL COLOR { REVERSE,UNDERLINE } are used instead.  This command",
+"  affects the entire current screen and terminal scrollback buffer.",
+" ",
+"SET TERMINAL ATTRIBUTE PROTECTED [ -",
+"   { BOLD, DIM, INVISIBLE, NORMAL, REVERSE, UNDERLINED } ]",
+"  Sets the attributes used to represent Protected text in Wyse and Televideo",
+"  terminal emulations.  Any combination of attributes may be used.  The",
+"  default is DIM.)",
+" ",
+#endif /* OS2 */
+
+#ifdef OS2
+#ifdef CK_XYZ
+"SET TERMINAL AUTODOWNLOAD { ON, OFF, ERROR { STOP, CONTINUE } }",
+"  enables/disables automatic switching into file-transfer mode when a Kermit",
+"  or ZMODEM file transfer has been detected during CONNECT mode or while",
+"  an INPUT command is active.  Default is OFF.",
+#else
+"SET TERMINAL AUTODOWNLOAD { ON, OFF, ERROR { STOP, CONTINUE } }",
+"  enables/disables automatic switching into file-transfer mode when a Kermit",
+"  file transfer has been detected during CONNECT mode or while an INPUT",
+"  command is active.  Default is OFF.",
+#endif /* CK_XYZ */
+
+" ",
+"  When TERMINAL AUTODOWNLOAD is ON, the TERMINAL AUTODOWNLOAD ERROR setting",
+"  tells what to do if an error occurs during a file transfer or other",
+"  protocol operation initiated by the terminal emulator: STOP (the default)",
+"  means to remain in command mode so you can see what happened; CONTINUE",
+"  means to resume the CONNECT session (e.g. so a far-end script can continue",
+"  its work).",
+" ",
+
+#ifdef CK_XYZ
+"SET TERM... AUTO... { KERMIT, ZMODEM } C0-CONFLICTS { IGNORED, PROCESSED }",
+"  Determines whether the active terminal emulator should process or ignore",
+"  C0 control characters which are also used for the specified file transfer",
+"  protocol.  Kermit by default uses ^A (SOH) and Zmodem uses ^X (CAN).",
+"  Default is PROCESSED.",
+" ",
+"SET TERM... AUTO... { KERMIT, ZMODEM } DETECTION-METHOD { PACKET, STRING }",
+"  Determines whether the specified file transfer protocol should be detected",
+"  by looking for valid packets or by identifying a specified text string.",
+"  Default is PACKET.",
+" ",
+"SET TERM... AUTO... { KERMIT, ZMODEM } STRING <text>",
+"  Lets you assign an autodownload detection string for use with the",
+"  specified file transfer protocol.",
+"  Default for Kermit is \"READY TO SEND...\", for Zmodem is \"rz\\{13}\".",
+" ",
+#else /* CK_XYZ */
+"SET TERM... AUTO... KERMIT C0-CONFLICTS { IGNORED, PROCESSED }",
+"  Determines whether the active terminal emulator should process or ignore",
+"  C0 control characters which are also used for the specified file transfer",
+"  protocol.  Kermit by default uses ^A <SOH>.  Default is PROCESSED.",
+" ",
+"SET TERM... AUTO... KERMIT DETECTION-METHOD { PACKET, STRING }",
+"  Determines whether the specified file transfer protocol should be detected",
+"  by looking for valid packets or by identifying a specified text string.",
+"  Default is PACKET.",
+" ",
+"SET TERM... AUTO... KERMIT STRING <text>",
+"  Lets you assign an autodownload detection string for use with the",
+"  specified file transfer protocol.  Default is \"READY TO SEND...\".",
+" ",
+#endif /* CK_XYZ */
+"SET TERMINAL AUTOPAGE { ON, OFF }",
+" ",
+"SET TERMINAL AUTOSCROLL { ON, OFF }",
+" ",
+#else /* OS2 */
+"SET TERMINAL AUTODOWNLOAD { ON, OFF, ERROR { STOP, CONTINUE } }",
+"  Enables/disables automatic switching into file-transfer mode when a valid",
+#ifdef CK_XYZ
+"  Kermit or ZMODEM packet of the appropriate type is received during CONNECT",
+"  mode.  Default is OFF.",
+#else
+"  Kermit packet of the appropriate type is received during CONNECT mode.",
+"  Default is OFF.",
+#endif /* CK_XYZ */
+
+" ",
+"  When TERMINAL AUTODOWNLOAD is ON, the TERMINAL AUTODOWNLOAD ERROR setting",
+"  tells what to do if an error occurs during a file transfer or other",
+"  protocol operation initiated by the terminal emulator: STOP (the default)",
+"  means to remain in command mode so you can see what happened; CONTINUE",
+"  means to resume the CONNECT session (e.g. so a far-end script can continue",
+"  its work).",
+" ",
+
+#endif /* OS2 */
+
+#ifdef OS2
+"SET TERMINAL BELL { AUDIBLE, VISIBLE, NONE }",
+"  Specifies how Control-G (bell) characters are handled.  AUDIBLE means",
+"  a beep is sounded; VISIBLE means the screen is flashed momentarily.",
+" ",
+"  (This command has been superseded by SET BELL.)",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL BYTESIZE { 7, 8 }",
+"  Use 7- or 8-bit characters between Kermit and the remote computer during",
+"  terminal sessions.  The default is 8.",
+" ",
+
+#ifndef NOCSETS
+#ifdef OS2
+"SET TERMINAL CHARACTER-SET <remote-cs>",
+"  Specifies the character set used by the remote host, <remote-cs>.",
+"  Equivalent to SET TERM REMOTE-CHARACTER-SET <remote-cs> ALL.  For more",
+"  control over the details, use SET TERM REMOTE-CHARACTER-SET and (in",
+"  non-GUI K95 versions) SET TERM LOCAL-CHARACTER-SET; these are explained",
+"  below.  The default TERMINAL CHARACTER-SET is LATIN1 (ISO 8859-1).",
+#else  /* not OS2 */
+"SET TERMINAL CHARACTER-SET <remote-cs> [ <local-cs> ]",
+"  Specifies the character set used by the remote host, <remote-cs>, and the",
+"  character set used by C-Kermit locally, <local-cs>.  If you don't specify",
+"  the local character set, the current FILE CHARACTER-SET is used.  When",
+"  you specify two different character sets, C-Kermit translates between them",
+"  during CONNECT.  By default, both character sets are TRANSPARENT, and",
+"  no translation is done.",
+#endif /* OS2 */
+" ",
+#endif /* NOCSETS */
+
+#ifdef OS2
+
+"SET TERMINAL CODE-PAGE <number>",
+"  Lets you change the PC code page.  Only works for code pages that are",
+"  successfully prepared in CONFIG.SYS.  Use SHOW TERMINAL to list the",
+"  current code page and the available code pages.",
+#ifdef OS2ONLY
+" ",
+"  Also see SET TERMINAL FONT if the desired code page in not available in",
+"  your version of OS/2.",
+#endif /* OS2ONLY */
+" ",
+
+#ifndef NT
+"SET TERMINAL COLOR BORDER <foreground>",
+#endif /* NT */
+"SET TERMINAL COLOR <screenpart> <foreground> <background>",
+" Sets the colors of the terminal emulation screen.",
+" <screenpart> may be any of the following:",
+"  DEBUG, HELP-TEXT, REVERSE, SELECTION, STATUS-LINE, TERMINAL-SCREEN, or",
+"  UNDERLINED-TEXT.",
+" <foreground> and <background> may be any of:",
+"  BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LGRAY, DGRAY, LBLUE,",
+"  LGREEN, LCYAN, LRED, LMAGENTA, YELLOW or WHITE.",
+" The L prefix for the color names means Light.",
+" ",
+
+"SET TERMINAL COLOR ERASE { CURRENT-COLOR, DEFAULT-COLOR }",
+"  Determines whether the current color as set by the host or the default",
+"  color as set by the user (SET TERMINAL COLOR TERMINAL) is used to clear",
+"  the screen when erase commands are received from the host.",
+" ",
+
+"SET TERMINAL COLOR RESET-ON-ESC[0m { CURRENT-COLOR, DEFAULT-COLOR }",
+"  Determines whether the current color or the default color is used after",
+"  <ESC>[0m (\"reset attributes\") command sequence is received from the",
+"  host.",
+" ",
+
+"SET TERMINAL CONTROLS { 7, 8 }",
+"  Determines whether VT220/320 or Wyse 370 function keys, arrow keys, etc,",
+"  that generate ANSI-format escape sequences should send 8-bit control",
+"  characters or 7-bit escape sequences.",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL CR-DISPLAY { CRLF, NORMAL }",
+"  Specifies how incoming carriage return characters are to be displayed",
+"  on your screen.",
+" ",
+
+#ifdef OS2
+#ifdef KUI
+"SET TERMINAL CURSOR { FULL, HALF, UNDERLINE } {ON, OFF, NOBLINK}",
+"  Selects the cursor style and visibility for the terminal screen.",
+#else
+"SET TERMINAL CURSOR { FULL, HALF, UNDERLINE } {ON, OFF}",
+"  Selects the cursor style and visibility for the terminal screen.",
+#endif /* KUI */
+" ",
+"SET TERMINAL DG-UNIX-MODE { ON, OFF }",
+"  Specifies whether the Data General emulations should accept control",
+"  sequences in Unix compatible format or in native DG format.  The",
+"  default is OFF, DG format.",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL DEBUG { ON, OFF }",
+"  Turns terminal session debugging on and off.  When ON, incoming control",
+"  characters are displayed symbolically, rather than be taken as formatting",
+"  commands.  SET TERMINAL DEBUG ON implies SET TELNET DEBUG ON.",
+" ",
+#ifdef OS2
+"SET TERMINAL DG-UNIX-MODE { ON, OFF }",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL ECHO { LOCAL, REMOTE }",
+"  Specifies which side does the echoing during terminal connection.",
+" ",
+
+"SET TERMINAL ESCAPE-CHARACTER { ENABLED, DISABLED }",
+"  Turns on/off the ability to escape back from CONNECT mode using the SET",
+#ifdef OS2
+"  ESCAPE character.  If you disable it you can still get back using Alt-key",
+"  combinations as shown in the status line.  Also see HELP SET ESCAPE.",
+#else
+"  ESCAPE character.  If you disable it, Kermit returns to its prompt only",
+"  when the connection is closed by the other end.  USE WITH EXTREME CAUTION.",
+"  Also see HELP SET ESCAPE.",
+#endif /* OS2 */
+" ",
+
+#ifdef OS2
+#ifdef KUI
+"SET TERMINAL FONT <facename> <height>",
+"  Specifies the font to be used in the Kermit 95 window.  The font is",
+"  determined by the choice of a facename and a height measured in Points.",
+"  The available facenames are those installed in the Font Control Panel.",
+" ",
+#else /* KUI */
+#ifdef OS2ONLY
+"SET TERMINAL FONT { CP437, CP850, CP852, CP862, CP866, DEFAULT }",
+"  CP437 - Original PC code page",
+"  CP850 - \"Multilingual\" (West Europe) code page",
+"  CP852 - East Europe Roman Alphabet code page (for Czech, Polish, etc)",
+"  CP862 - Hebrew code page",
+"  CP866 - Cyrillic (Russian, Belorussian, and Ukrainian) code page",
+" ",
+"  Loads a soft into the video adapter for use during terminal emulation.",
+"  Use this command when your OS/2 system does not have the desired code.",
+"  page.  Can be used only in full-screen sessions.  Also see SET TERMINAL",
+"  CODE-PAGE and SET TERMINAL REMOTE-CHARACTER-SET.",
+" ",
+#endif /* OS2ONLY */
+#endif /* KUI */
+
+#ifdef NT
+"SET TERMINAL HEIGHT <number>",
+"  Changes the number of rows (lines) to use during terminal emulation, not",
+"  counting the status line.  Recommended values are 24, 42, and 49 (or 25,",
+"  43, and 50 if SET TERMINAL STATUSLINE is OFF.)",
+#else
+"SET TERMINAL HEIGHT <number>"
+"  Changes the number of rows (lines) to use during terminal emulation, not",
+"  counting the status line.  Windowed sessions can use any value from 8 to",
+"  101.  Fullscreen sessions are limited to 24, 42, 49, or 59.  Not all"
+"  heights are supported by all video adapters.",
+#endif /* NT */
+#else  /* OS2 */
+"SET TERMINAL HEIGHT <number>",
+"  Tells C-Kermit how many rows (lines) are on your CONNECT-mode screen.",
+#endif /* OS2 */
+" ",
+
+#ifdef CKTIDLE
+"SET TERMINAL IDLE-TIMEOUT <number>",
+"  Sets the limit on idle time in CONNECT mode to the given number of",
+"  seconds.  0 (the default) means no limit.",
+" ",
+"SET TERMINAL IDLE-ACTION { EXIT, HANGUP, OUTPUT [ text ], RETURN }",
+"  Specifies the action to be taken when a CONNECT session is idle for the",
+"  number of seconds given by SET TERMINAL IDLE-TIMEOUT.  The default action",
+"  is to RETURN to command mode.  EXIT exits from Kermit; HANGUP hangs up the",
+"  connection, and OUTPUT sends the given text to the host without leaving",
+"  CONNECT mode; if no text is given a NUL (0) character is sent.",
+#ifdef TNCODE
+" ",
+"And for Telnet connections:",
+" ",
+"SET TERMINAL IDLE-ACTION { TELNET-NOP, TELNET-AYT }",
+"  Sends the indicated Telnet protocol message: No Operation (NOP) or",
+"  \"Are You There?\" (AYT).",
+#endif /* TNCODE */
+" ",
+#endif /* CKTIDLE */
+
+#ifdef OS2
+
+"SET TERMINAL KDB-FOLLOWS-GL/GR { ON, OFF }",
+" Specifies whether or not the keyboard character set should follow the",
+"  active GL and GR character sets.  This feature is OFF by default and",
+"  should not be used unless it is specificly required by the host",
+"  application.",
+" ",
+
+"SET TERMINAL KEY <mode> /LITERAL <keycode> <text>",
+"SET TERMINAL KEY <mode> DEFAULT",
+"SET TERMINAL KEY <mode> CLEAR",
+"  Configures the key whose <keycode> is given to send the given text when",
+"  pressed while <mode> is active.  <mode> may be any of the valid terminal",
+"  types or the special modes \"EMACS\", \"HEBREW\" or \"RUSSIAN\".  DEFAULT",
+"  restores all default key mappings for the specified mode.  CLEAR erases",
+"  all the key mappings.  If there is no text, the default key binding is",
+#ifndef NOCSETS
+"  restored for the key k.  SET TERMINAL KEY mappings take place before",
+"  terminal character-set translation.  SET KEY mappings take precedence over",
+"  SET TERMINAL KEY <terminal type> settings.",
+#else
+"  restored for the key.  SET KEY mappings take precedence over SET TERMINAL",
+"  KEY <terminal type> settings.",
+#endif /* NOCSETS */
+"  The /LITERAL switch may be used to instruct Kermit to ignore character-set",
+"  translations when sending this definition to the host.",
+" ",
+"  The text may contain \"\\Kverbs\" to denote actions, to stand for DEC",
+"  keypad, function, or editing keys, etc.  For a list of available keyboard",
+"  verbs, type SHOW KVERBS.",
+" ",
+"  To find out the keycode and mapping for a particular key, use the SHOW",
+"  KEY command.  Use the SAVE KEYS command to save all settings to a file.",
+" ",
+"SET TERMINAL KEYBOARD-MODE { NORMAL, EMACS, RUSSIAN, HEBREW }",
+"  Select a special keyboard mode for use in the terminal screen.",
+" ",
+
+"SET TERMINAL KEYPAD-MODE { APPLICATION, NUMERIC }",
+"  Specifies the \"mode\" of the numeric keypad for VT terminal emulation.",
+"  Use this command in case the host or application wants the keypad to be",
+"  in a different mode than it's in, but did not send the escape sequence",
+"  to put it in the needed mode.",
+" ",
+#ifdef KUI
+"SET TERMINAL LINE-SPACING <float>",
+"  Specifies the line spacing used when displaying text.  The default is 1.0.",
+"  Valid values range from 1.0 to 3.0 inclusive.",
+" ",
+#endif /* KUI */
+#endif /* OS2 */
+
+#ifndef NOCSETS
+#ifdef OS2
+"SET TERMINAL LOCAL-CHARACTER-SET <local-cs>",
+"  Specifies the character set used by K-95 locally.  If you don't specify",
+#ifdef OS2ONLY
+"  the local character-set, the current TERMINAL FONT is used if you have",
+"  given a SET TERMINAL FONT command; otherwise the current codepage is used.",
+#else
+"  the local character-set, the current code page is used.",
+#endif /* OS2ONLY */
+" ",
+"  When the local and remote character sets differ, Kermit translates between",
+"  them during CONNECT.  By default, the remote character set is Latin1 and",
+"  the local one is your current code page.",
+#ifdef NT
+" ",
+"  In Windows NT, Unicode is used as the local character-set regardless of",
+"  this setting.",
+#endif /* NT */
+" ",
+"See also SET TERMINAL REMOTE-CHARACTER-SET",
+" ",
+#endif /* OS2 */
+#endif /* NOCSETS */
+
+#ifdef OS2
+"SET TERMINAL LOCKING-SHIFT { OFF, ON }",
+"  Tells whether to send Shift-In/Shift-Out (Ctrl-O and Ctrl-N) to switch",
+"  between 7-bit and 8-bit characters sent during terminal emulation over",
+"  7-bit connections.  OFF by default.",
+#else
+"SET TERMINAL LOCKING-SHIFT { OFF, ON }",
+"  Tells Kermit whether to use Shift-In/Shift-Out (Ctrl-O and Ctrl-N) to",
+"  switch between 7-bit and 8-bit characters during CONNECT.  OFF by default.",
+#endif /* OS2 */
+" ",
+
+#ifdef OS2
+"SET TERMINAL MARGIN-BELL { ON [column], OFF }",
+"  Determines whether the margin-bell is activated and what column it should",
+"  ring at.  OFF by default.",
+" ",
+#endif /* OS2 */
+
+"SET TERMINAL NEWLINE-MODE { OFF, ON }",
+"  Tells whether to send CRLF (Carriage Return and Line Feed) when you type",
+"  CR (press the Return or Enter key) in CONNECT mode.",
+" ",
+
+#ifdef OS2
+"SET TERMINAL OUTPUT-PACING <milliseconds>",
+"  Tells how long to pause between sending each character to the host during",
+"  CONNECT mode.  Normally not needed but sometimes required to work around",
+"  TRANSMISSION BLOCKED conditions when pasting into the terminal window.",
+" ",
+
+#ifdef PCTERM
+"SET TERMINAL PCTERM { ON, OFF }",
+"  Activates or deactivates the PCTERM terminal emulation keyboard mode.",
+"  When PCTERM is ON all keystrokes in the terminal screen are sent to the",
+"  host as make/break (down/up) codes instead of as characters from the",
+"  REMOTE-CHARACTER-SET, and all keyboard mappings, including Kverbs and the",
+"  escape character are disabled.  To turn off PCTERM keyboard mode while in",
+"  CONNECT mode press Control-CapsLock.  PCTERM is OFF by default.",
+" ",
+#endif /* PCTERM */
+#endif /* OS2 */
+
+#ifdef OS2
+"SET TERMINAL PRINT { AUTO, COPY, OFF, USER }",
+"  Allows selective control of various types of printing from the Terminal",
+"  session.  AUTO prints a line of text from the terminal screen whenever",
+"  the cursor is moved off the line.  COPY prints every byte received as",
+"  it is received without interpretation.  USER prints every byte after",
+"  interpretation by the terminal emulator translates character-sets and",
+"  construct escape sequences, ...  The default is OFF.",
+" ",
+#else
+#ifdef XPRINT
+"SET TERMINAL PRINT { ON, OFF }",
+"  Enables and disables host-initiated transparent printing in CONNECT mode.",
+" ",
+#endif /* XPRINT */
+#endif /* OS2 */
+
+#ifdef OS2
+#ifndef NOCSETS
+"SET TERMINAL REMOTE-CHARACTER-SET <remote-cs> [ { G0,G1,G2,G3 }... ]",
+"  Specifies the character set used by the remote host, <remote-cs>.",
+"  When the local and remote character sets differ, Kermit translates",
+"  between them during CONNECT.  By default, the remote character set is",
+"  Latin1 and the local one is your current code page.  Optionally, you can",
+"  also designate the character set to the G0..G3 graphic tables.",
+" ",
+#endif /* NOCSETS */
+#endif /* OS2 */
+
+#ifdef OS2
+"SET TERMINAL ROLL-MODE { INSERT, OVERWRITE, KEYSTROKES [ option ] }",
+"  Tells whether new data when received from the host is entered into the",
+"  scrollback buffer at the current rollback position (OVERWRITE) or at the",
+"  end of the buffer (INSERT).  The default is INSERT.  Typing is allowed",
+"  during rollbacks in either mode, according to SET TERM ROLL KEYSTROKES:",
+"  SEND (the default) means to process keystrokes normally; IGNORE means to",
+"  ignore them when the screen is scrolled back; RESTORE-AND-SEND is like",
+"  SEND but restores the screen to its active position first.",
+" ",
+
+"SET TERMINAL SCREEN-MODE { NORMAL, REVERSE }",
+"  When set to REVERSE the foreground and background colors are swapped as",
+"  well as the application of the foreground and background intensity bits.",
+"  The default is NORMAL.",
+" ",
+
+"SET TERMINAL SCREEN-OPTIMIZE { ON, OFF }",
+"  When set to ON, the default, Kermit only paints the screen with characters",
+"  that have changed since the last screen paint.  When OFF, the screen is",
+"  completely repainted each time there is a change.",
+" ",
+
+"SET TERMINAL SCREEN-UPDATE { FAST, SMOOTH } [ <milliseconds> ]",
+"  Chooses the mechanism used for screen updating and the update frequency.",
+"  Defaults are FAST scrolling with updates every 100 milliseconds.",
+" ",
+
+"SET TERMINAL SCROLLBACK <lines>",
+"  Sets size of CONNECT virtual screen buffer.  <lines> includes the active",
+"  terminal screen.  The minimum is 256.  The maximum is 2 million.  The",
+"  default is 2000.",
+" ",
+
+"SET TERMINAL SEND-DATA { ON, OFF }",
+"  Determines whether ASCII emulations such as WYSE 30,50,60 or TVI 910+,925,",
+"  950 may send their screen contents to the host upon request.  Allowing the",
+"  screen to be read by the host is a significant security risk.  The default",
+"  is OFF and should only be changed after a security evaluation of host",
+"  environment.",
+" ",
+
+"SET TERMINAL SEND-END-OF-BLOCK { CRLF_ETX, US_CR }",
+"  Determines which set of characters should be used as end of line and end",
+"  of transmission indicators when sending screen data to the host",
+" ",
+
+"SET TERMINAL SGR-COLORS { ON, OFF }",
+"  ON (default) means allow host control of colors; OFF means ignore host",
+"  escape sequences to set color.",
+" ",
+
+"SET TERMINAL SNI-CH.CODE { ON, OFF }",
+"  This command controls the state of the CH.CODE key.  It is the equivalent",
+"  to the SNI_CH_CODE Keyboard verb.  The SNI terminal uses CH.CODE to",
+"  easily switch between the National Language character set and U.S. ASCII.",
+"  The default is ON which means to display characters as U.S. ASCII.  When",
+"  OFF the lanuage specified by SET TERMINAL SNI-LANUAGE is used to display",
+"  characters when 7-bit character sets are in use."
+" ",
+"SET TERMINAL SNI-FIRMWARE-VERSIONS <kbd-version> <terminal-version>",
+"  Specifies the Firmware Version number that should be reported to the host",
+"  when the terminal is queried.  The default is 920031 for the keyboard",
+"  and 830851 for the terminal.",
+" ",
+"SET TERMINAL SNI-LANGUAGE <national-language>",
+"  An alias for SET TERMINAL VT-LANUAGE, this command specifies the national",
+"  language character-set that should be used when the NRC mode is activated",
+"  for VT emulations or when CH.CODE is OFF for SNI emulations.  The default",
+"  language for SET TERMINAL TYPE SNI-97801 is \"German\".",
+" ",
+"SET TERMINAL SNI-PAGEMODE { ON, OFF }",
+"  Determines whether or not page mode is active.  OFF by default.",
+" ",
+"SET TERMINAL SNI-SCROLLMODE { ON, OFF }",
+"  Determines whether or not scroll mode is active.  OFF by default.",
+" ",
+"SET TERMINAL STATUSLINE { ON, OFF }",
+"  ON (default) enables the Kermit status line in the terminal screen.",
+"  OFF removes it, making the line available for use by the host.",
+" ",
+
+"SET TERMINAL TRANSMIT-TIMEOUT <seconds>",
+"  Specifies the maximum amount of time K-95 waits before returning to the",
+"  prompt if your keystrokes can't be transmitted for some reason, such as a",
+"  flow-control deadlock.",
+" ",
+#endif /* OS2 */
+
+#ifdef CK_TRIGGER
+"SET TERMINAL TRIGGER <string>",
+"  Specifies a string that, when detected during any subsequent CONNECT",
+"  session, is to cause automatic return to command mode.  Give this command",
+"  without a string to cancel the current trigger.  See HELP CONNECT for",
+"  additional information.",
+" ",
+#endif /* CK_TRIGGER */
+
+#ifdef OS2
+"SET TERMINAL URL-HIGHLIGHT { ON <attribute>, OFF }",
+"  Specifies whether K-95 should highlight URLs and which screen attribute",
+"  should be used.  The screen attributes can be one of NORMAL, BLINK, BOLD,",
+"  DIM, INVISIBLE, REVERSE, or UNDERLINE.  The default is ON using the",
+"  BOLD screen attribute.",
+" ",
+"SET TERMINAL VIDEO-CHANGE { DISABLED, ENABLED }",
+"  Specifies whether K-95 should change video modes automatically in response",
+#ifdef NT
+"  to escape sequences from the other computer.  ENABLED by default (except",
+"  on Windows 95).",
+#else /* NT */
+"  to escape sequences from the other computer.  ENABLED by default.",
+#endif /* NT */
+" ",
+
+"SET TERMINAL VT-LANGUAGE <language>",
+"  Specifies the National Replacement Character Set (NRC) to be used when",
+"  NRC mode is activated.  The default is \"North American\".",
+" ",
+"SET TERMINAL VT-NRC-MODE { ON, OFF }",
+"  OFF (default) chooses VT multinational Character Set mode.  OFF chooses",
+"  VT National Replacement Character-set mode.  The NRC is selected with",
+"  SET TERMINAL VT-LANGUAGE",
+" ",
+
+#ifdef NT
+"SET TERMINAL WIDTH <cols>",
+"  Tells the number of columns in the terminal screen.",
+" ",
+"  The default is 80.  You can also use 132.  Other widths can be chosen but",
+"  are usually not supported by host software.",
+" ",
+#else
+"SET TERMINAL WIDTH <cols>",
+"  Tells how many columns define the terminal size.",
+" ",
+"Default is 80.  In Windowed OS/2 2.x sessions, this value may not be changed",
+"In Windowed OS/2 WARP 3.x sessions, this value may range from 20 to 255.",
+"In Full screen sessions, values of 40, 80, and 132 are valid.  Not all",
+"combinations of height and width are supported on all adapters.",
+" ",
+#endif /* NT */
+"SET TERMINAL WRAP { OFF, ON }",
+"  Tells whether the terminal emulator should automatically wrap long lines",
+"  on your screen.",
+" ",
+#else
+
+"SET TERMINAL WIDTH <number>",
+" \
+Tells Kermit how many columns (characters) are on your CONNECT-mode screen.",
+" ",
+#endif /* OS2 */
+"Type SHOW TERMINAL to see current terminal settings.",
+"" };
+#endif /* NOLOCAL */
+
+#ifdef NETCONN
+static char *hxyhost[] = {
+"SET HOST [ switches ] hostname-or-address [ service ] [ protocol-switch ]",
+"  Establishes a connection to the specified network host on the currently",
+"  selected network type.  For TCP/IP connections, the default service is",
+"  TELNET; specify a different TCP port number or service name to choose a",
+"  different service.  The first set of switches can be:",
+" ",
+" /NETWORK-TYPE:name",
+"   Makes the connection on the given type of network.  Equivalent to SET",
+"   NETWORK TYPE name prior to SET HOST, except that the selected network",
+"   type is used only for this connection.  Type \"set host /net:?\" to see",
+#ifdef NETCMD
+"   a list.  /NETWORK-TYPE:COMMAND means to make the connection through the",
+"   given system command, such as \"rlogin\" or \"cu\".",
+#else
+"   a list.",
+#endif /* NETCMD */
+" ",
+" /CONNECT",
+"   \
+Enter CONNECT (terminal) mode automatically if the connection is successful.",
+" ",
+" /SERVER",
+"   Enter server mode automatically if the connection is successful.",
+" ",
+" /USERID:[<name>]",
+"   This switch is equivalent to SET LOGIN USERID <name> or SET TELNET",
+"   ENVIRONMENT USER <name>.  If a string is given, it sent to host during",
+"   Telnet negotiations; if this switch is given but the string is omitted,",
+"   no user ID is sent to the host.  If this switch is not given, your",
+"   current USERID value, \\v(userid), is sent.  When a userid is sent to the",
+"   host it is a request to login as the specified user.",
+" ",
+#ifdef CK_AUTHENTICATION
+" /PASSWORD:[<string>]",
+"   This switch is equivalent to SET LOGIN PASSWORD.  If a string is given,",
+"   it is treated as the password to be used (if required) by any Telnet",
+"   Authentication protocol (Kerberos Ticket retrieval, Secure Remote",
+"   Password, or X.509 certificate private key decryption.)  If no password",
+"   switch is specified a prompt is issued to request the password if one",
+"   is required for the negotiated authentication method.",
+" ",
+#endif /* CK_AUTHENTICATION */
+"The protocol-switches can be:",
+" ",
+" /NO-TELNET-INIT",
+"   Do not send initial Telnet negotiations even if this is a Telnet port.",
+" ",
+" /RAW-SOCKET",
+"   This is a connection to a raw TCP socket.",
+" ",
+#ifdef RLOGCODE
+" /RLOGIN",
+"   Use Rlogin protocol even if this is not an Rlogin port.",
+" ",
+#endif /* RLOGCODE */
+" /TELNET",
+"   Send initial Telnet negotiations even if this is not a Telnet port.",
+" ",
+#ifdef CK_KERBEROS
+#ifdef RLOGCODE
+#ifdef KRB4
+" /K4LOGIN",
+"   Use Kerberos IV klogin protocol even if this is not a klogin port.",
+" ",
+#ifdef CK_ENCRYPTION
+" /EK4LOGIN",
+"   Use Kerberos IV Encrypted login protocol even if this is not an eklogin",
+"   port.",
+" ",
+#endif /* CK_ENCRYPTION */
+#endif /* KRB4 */
+#ifdef KRB5
+" /K5LOGIN",
+"   Use Kerberos V klogin protocol even if this is not a klogin port.",
+" ",
+#ifdef CK_ENCRYPTION
+" /EK5LOGIN",
+"   Use Kerberos V Encrypted login protocol even if this is not an eklogin",
+"   port.",
+" ",
+#endif /* CK_ENCRYPTION */
+#endif /* KRB5 */
+#endif /* RLOGCODE */
+#endif /* CK_KERBEROS */
+#ifdef CK_SSL
+" /SSL",
+"   Perform SSL negotiations.",
+" ",
+" /SSL-TELNET",
+"   Perform SSL negotiations and if successful start Telnet negotiations.",
+" ",
+" /TLS",
+"   Perform TLS negotiations.",
+" ",
+" /TLS-TELNET",
+"   Perform TLS negotiations and if successful start Telnet negotiations.",
+" ",
+#endif /* CK_SSL */
+"Examples:",
+"  SET HOST kermit.columbia.edu",
+"  SET HOST /CONNECT kermit.columbia.edu",
+"  SET HOST * 1649",
+"  SET HOST /SERVER * 1649",
+"  SET HOST 128.59.39.2",
+"  SET HOST madlab.sprl.umich.edu 3000",
+"  SET HOST xyzcorp.com 2000 /RAW-SOCKET",
+#ifdef SSHBUILTIN
+"  SET HOST /NET:SSH kermit.columbia.edu /x11-forwarding:on", 
+#endif /* SSHBUILTIN */
+#ifdef NETCMD
+"  SET HOST /CONNECT /COMMAND rlogin xyzcorp.com",
+#endif /* NETCMD */
+" ",
+#ifdef SUPERLAT
+"Notes:",
+" ",
+" . The TELNET command is equivalent to SET NETWORK TYPE TCP/IP,",
+"   SET HOST name [ port ] /TELNET, IF SUCCESS CONNECT",
+" ",
+" . For SUPERLAT connections, the hostname-or-address may be either a service",
+"   name, or a node/port combination, as required by your LAT host.",
+#else
+"The TELNET command is equivalent to SET NETWORK TYPE TCP/IP,",
+"SET HOST name [ port ] /TELNET, IF SUCCESS CONNECT",
+#endif /* SUPERLAT */
+" ",
+"Also see SET NETWORK, TELNET, SET TELNET.",
+"" };
+
+static char *hmxyauth[] = {
+"Synatx: SET AUTHENTICATION <auth_type> <parameter> <value>",
+"  Sets defaults for the AUTHENTICATE command:",
+" ",
+#ifdef CK_KERBEROS
+"SET AUTHENTICATION KERBEROS5 ADDRESSES {list of ip-addresses}",
+"  Specifies a list of IP addresses that should be placed in the Ticket",
+"  Getting Ticket in addition to the local machine addresses.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } AUTODESTROY",
+"  { ON-CLOSE, ON-EXIT, NEVER }",
+"  When ON, Kermit will destroy all credentials in the default",
+"  credentials cache upon Kermit termination.  Default is NEVER.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } AUTOGET { ON, OFF }",
+"  When ON, if the host offers Kerberos 4 or Kerberos 5 authentication",
+"  and Kermit is configured to use that authentication method and there",
+"  is no TGT, Kermit will automatically attempt to retrieve one by",
+"  prompting for the password (and principal if needed.)  Default is ON.",
+" ",
+"SET AUTHENTICATION KERBEROS5 CREDENTIALS-CACHE <filename>",
+"  Allows an alternative credentials cache to be specified.  This is useful",
+"  when you need to maintain two or more sets of credentials for different",
+"  realms or roles.  The default is specified by the environment variable",
+"  KRB5CCNAME or as reported by the Kerberos 5 library.",
+" ",
+"SET AUTHENTICATION KERBEROS5 FORWARDABLE { ON, OFF }",
+"  When ON, specifies that Kerberos 5 credentials should be forwardable to",
+"  the host.  If SET TELNET AUTHENTICATION FORWARDING is ON, forwardable",
+"  credentials are sent to the host.  The default is OFF.",
+" ",
+"SET AUTHENTICATION KERBEROS5 GET-K4-TGT { ON, OFF }",
+"  When ON, specifies that Kerberos 4 credentials should be requested each",
+"  time Kerberos 5 credentials are requested with AUTH KERBEROS5 INIT.",
+"  Default is OFF.",
+" ",
+"SET AUTHENTICATION KERBEROS4 INSTANCE <instance>",
+"  Allows a Kerberos 4 instance to be specified as a default (if needed).",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } KEYTAB <filename>",
+"  Specifies the location of the keytab file used to authenticate incoming",
+"  connections.  The default is none, which means to use the default value",
+"  configured in the Kerberos installation.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } LIFETIME <minutes>",
+"  Specifies the lifetime of the TGTs requested from the KDC.  The default",
+"  is 600 minutes (10 hours).",
+" ",
+"SET AUTHENTICATION KERBEROS5 NO-ADDRESSES { ON, OFF }",
+"  Specifies whether or not IP addresses will be inserted into the TGT."
+"  Default is OFF.",
+" ",
+"SET AUTHENTICATION KERBEROS4 PREAUTH { ON, OFF }",
+"  Allows Kerberos 4 preauthenticated TGT requests to be turned off.  The",
+"  default is ON.  Only use if absolutely necessary.  We recommend that",
+"  preauthenticated requests be required for all tickets returned by a KDC",
+"  to a requestor.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } PRINCIPAL <name>",
+"  When Kermit starts, it attempts to set the principal name to that stored",
+"  in the current credentials cache.  If no credential cache exists, the",
+"  current SET LOGIN USERID value is used.  SET LOGIN USERID is set to the",
+"  operating system's current username when Kermit is started.  To force",
+"  Kermit to prompt the user for the principal name when requesting TGTs,",
+"  place:",
+" ",
+"    SET AUTH K4 PRINCIPAL {}",
+"    SET AUTH K5 PRINCIPAL {}",
+" ",
+"  in the Kermit initialization file or connection script.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } PROMPT PASSWORD <prompt>",
+"  Specifies a custom prompt to be used when prompting for a password.",
+"  The Kerberos prompt strings may contain two %s replacement fields.",
+"  The first %s is replaced by the principal name; the second by the realm.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } PROMPT PRINCIPAL <prompt>",
+"  Specifies a custom prompt to be used when prompting for the Kerberos",
+"  principal name.  No %s replacement fields may be used.  Kermit prompts",
+"  for a principal name when retrieving a TGT if the command:",
+" ",
+"    SET AUTHENTICATION { KERBEROS4, KERBEROS5 } PRINCIPAL {}",
+" ",
+"  has been issued.",
+" ",
+"SET AUTHENTICATION KERBEROS5 PROXIABLE { ON, OFF }",
+"  When ON, specifies that Kerberos 5 credentials should be proxiable.",
+"  Default is OFF.",
+" ",
+"SET AUTHENTICATION KERBEROS5 RENEWABLE <minutes>",
+"  When <minutes> is greater than the ticket lifetime a TGT may be renewed",
+"  with AUTH K5 INIT /RENEW instead of getting a new ticket as long as the",
+"  ticket is not expired and its within the renewable lifetime.  Default is",
+"  0 (zero) minutes.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } REALM <name>",
+"  If no default is set, the default realm configured for the Kerberos",
+"  libraries is used.  Abbreviations accepted.",
+" ",
+"SET AUTHENTICATION { KERBEROS4, KERBEROS5 } SERVICE-NAME <name>",
+"  This command specifies the service ticket name used to authenticate",
+"  to the host when Kermit is used as a client; or the service ticket",
+"  name accepted by Kermit when it is acting as the host.",
+"  If no default is set, the default service name for Kerberos 4 is",
+"  \"rcmd\" and for Kerberos 5 is \"host\".",
+" ",
+#endif /* CK_KERBEROS */
+#ifdef CK_SRP
+"SET AUTHENTICATION SRP PROMPT PASSWORD <prompt>",
+"  Specifies a custom prompt to be used when prompting for a password.",
+"  The SRP prompt string may contain one %s replacement fields which is",
+"  replaced by the login userid.",
+" ",
+#endif /* CK_SRP */
+#ifdef CK_SSL
+"In all of the following commands \"SSL\" and \"TLS\" are aliases.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } CIPHER-LIST <list of ciphers>",
+"Applies to both SSL and TLS.  A colon separated list of any of the following",
+"(case sensitive) options depending on the options chosen when OpenSSL was ",
+"compiled: ",
+" ",
+"  Key Exchange Algorithms:",
+"    \"kRSA\"      RSA key exchange",
+"    \"kDHr\"      Diffie-Hellman key exchange (key from RSA cert)",
+"    \"kDHd\"      Diffie-Hellman key exchange (key from DSA cert)",
+"    \"kEDH\"      Ephemeral Diffie-Hellman key exchange (temporary key)",
+"    \"kKRB5\"     Kerberos 5",
+" ",
+"  Authentication Algorithm:",
+"    \"aNULL\"     No authentication",
+"    \"aRSA\"      RSA authentication",
+"    \"aDSS\"      DSS authentication",
+"    \"aDH\"       Diffie-Hellman authentication",
+"    \"aKRB5\"     Kerberos 5",
+" ",
+"  Cipher Encoding Algorithm:",
+"    \"eNULL\"     No encodiing",
+"    \"DES\"       DES encoding",
+"    \"3DES\"      Triple DES encoding",
+"    \"RC4\"       RC4 encoding",
+"    \"RC2\"       RC2 encoding",
+"    \"IDEA\"      IDEA encoding",
+" ",
+"  MAC Digest Algorithm:",
+"    \"MD5\"       MD5 hash function",
+"    \"SHA1\"      SHA1 hash function",
+"    \"SHA\"       SHA hash function (should not be used)",
+" ",
+"  Aliases:",
+"    \"SSLv2\"     all SSL version 2.0 ciphers (should not be used)",
+"    \"SSLv3\"     all SSL version 3.0 ciphers",
+"    \"EXP\"       all export ciphers (40-bit)",
+"    \"EXPORT56\"  all export ciphers (56-bit)",
+"    \"LOW\"       all low strength ciphers (no export)",
+"    \"MEDIUM\"    all ciphers with 128-bit encryption",
+"    \"HIGH\"      all ciphers using greater than 128-bit encryption",
+"    \"RSA\"       all ciphers using RSA key exchange",
+"    \"DH\"        all ciphers using Diffie-Hellman key exchange",
+"    \"EDH\"       all ciphers using Ephemeral Diffie-Hellman key exchange",
+"    \"ADH\"       all ciphers using Anonymous Diffie-Hellman key exchange",
+"    \"DSS\"       all ciphers using DSS authentication",
+"    \"KRB5\"      all ciphers using Kerberos 5 authentication",
+"    \"NULL\"      all ciphers using no encryption",
+" ",
+"Each item in the list may include a prefix modifier:",
+" ",
+"    \"+\"         move cipher(s) to the current location in the list",
+"    \"-\"         remove cipher(s) from the list (may be added again by",
+"                a subsequent list entry)",
+"    \"!\"         kill cipher from the list (it may not be added again",
+"                by a subsequent list entry)",
+" ",
+"If no modifier is specified the entry is added to the list at the current ",
+"position.  \"+\" may also be used to combine tags to specify entries such as "
+,
+"\"RSA+RC4\" describes all ciphers that use both RSA and RC4.",
+" ",
+"For example, all available ciphers not including ADH key exchange:",
+" ",
+"  ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP",
+" ",
+"All algorithms including ADH and export but excluding patented algorithms: ",
+" ",
+"  HIGH:MEDIUM:LOW:EXPORT56:EXP:ADH:!kRSA:!aRSA:!RC4:!RC2:!IDEA",
+" ",
+"The OpenSSL command ",
+" ",
+"  openssl.exe ciphers -v <list of ciphers> ",
+" ",
+"may be used to list all of the ciphers and the order described by a specific",
+"<list of ciphers>.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } CRL-DIR <directory>",
+"specifies a directory that contains certificate revocation files where each",
+"file is named by the hash of the certificate that has been revoked.",
+" ",
+"  OpenSSL expects the hash symlinks to be made like this:",
+" ",
+"    ln -s crl.pem `openssl crl -hash -noout -in crl.pem`.r0",
+" ",
+"  Since not all file systems have symlinks you can use the following command",
+"  in Kermit to copy the crl.pem file to the hash file name.",
+" ",
+"     copy crl.pem {\\fcommand(openssl.exe crl -hash -noout -in crl.pem).r0}",
+" ",
+"  This produces a hash based on the issuer field in the CRL such ",
+"  that the issuer field of a Cert may be quickly mapped to the ",
+"  correct CRL.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } CRL-FILE <filename>",
+"specifies a file that contains a list of certificate revocations.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DEBUG { ON, OFF }",
+"specifies whether debug information should be displayed about the SSL/TLS",
+"connection.  When DEBUG is ON, the VERIFY command does not terminate",
+"connections when set to FAIL-IF-NO-PEER-CERT when a certificate is",
+"presented that cannot be successfully verified.  Instead each error",
+"is displayed but the connection automatically continues.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DH-PARAM-FILE <filename>",
+"  Specifies a file containing DH parameters which are used to generate",
+"  temporary DH keys.  If a DH parameter file is not provided Kermit uses a",
+"  fixed set of parameters depending on the negotiated key length.  Kermit",
+"  provides DH parameters for key lengths of 512, 768, 1024, 1536, and 2048",
+"  bits.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DSA-CERT-CHAIN-FILE <filename>",
+"  Specifies a file containing a DSA certificate chain to be sent along with",
+"  the DSA-CERT to the peer.  This file must only be specified if Kermit is",
+"  being used as a server and the DSA certificate was signed by an",
+"  intermediary certificate authority.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DSA-CERT-FILE <filename>",
+"  Specifies a file containing a DSA certificate to be sent to the peer to ",
+"  authenticate the host or end user.  The file may contain the matching DH ",
+"  private key instead of using the DSA-KEY-FILE command.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } DSA-KEY-FILE <filename>",
+"Specifies a file containing the private DH key that matches the DSA ",
+"certificate specified with DSA-CERT-FILE.  This command is only necessary if",
+"the private key is not appended to the certificate in the file specified by",
+"DSA-CERT-FILE.",
+" ",
+"  Note: When executing a script in the background or when it is",
+"  running as an Internet Kermit Service Daemon, Kermit cannot support ",
+"  encrypted private keys.  When attempting to load a private key that is",
+"  encrypted, a prompt will be generated requesting the passphrase necessary",
+"  to decrypt the keyfile.  To automate access to the private key you must",
+"  decrypt the encrypted keyfile and create an unencrypted keyfile for use",
+"  by Kermit.  This can be accomplished by using the following command and",
+"  the passphrase:",
+" ",
+"  openssl dsa -in <encrypted-key-file> -out <unencrypted-key-file>",
+" ",
+"SET AUTHENTICATION { SSL, TLS } RANDOM-FILE <filename>",
+"  Specifies a file containing random data to be used as seed for the",
+"  Pseudo Random Number Generator.  The contents of the file are",
+"  overwritten with new random data on each use.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } RSA-CERT-CHAIN-FILE <filename>",
+"  Specifies a file containing a RSA certificate chain to be sent along with",
+"  the RSA-CERT to the peer.  This file must only be specified if Kermit is",
+"  being used as a server and the RSA certificate was signed by an",
+"  intermediary certificate authority.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } RSA-CERT-FILE <filename>",
+"  Specifies a file containing a RSA certificate to be sent to the peer to ",
+"  authenticate the host or end user.  The file may contain the matching RSA ",
+"  private key instead of using the RSA-KEY-FILE command.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } RSA-KEY-FILE <filename>",
+"  Specifies a file containing the private RSA key that matches the RSA",
+"  certificate specified with RSA-CERT-FILE.  This command is only necessary",
+"  if the private key is not appended to the certificate in the file specified"
+,
+"  by RSA-CERT-FILE.  ",
+" ",
+"  Note: When executing a script in the background or when it is",
+"  running as an Internet Kermit Service Daemon, Kermit cannot support ",
+"  encrypted private keys.  When attempting to load a private key that is",
+"  encrypted, a prompt will be generated requesting the passphrase necessary",
+"  to decrypt the keyfile.  To automate access to the private key you must",
+"  decrypt the encrypted keyfile and create an unencrypted keyfile for use",
+"  by Kermit.  This can be accomplished by using the following command and",
+"  the passphrase:",
+" ",
+"  openssl rsa -in <encrypted-key-file> -out <unencrypted-key-file>",
+" ",
+"SET AUTHENTICATION { SSL, TLS } VERBOSE { ON, OFF }",
+"  Specifies whether information about the authentication (ie, the",
+"  certificate chain) should be displayed upon making a connection.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } VERIFY { NO,PEER-CERT,FAIL-IF-NO-PEER-CERT }",
+"  Specifies whether certificates should be requested from the peer verified;",
+"  whether they should be verified when they are presented; and whether they",
+"  should be required.  When set to NO (the default for IKSD), Kermit does",
+"  not request that the peer send a certificate; if one is presented it is",
+"  ignored.  When set to PEER-CERT (the default when not IKSD), Kermit",
+"  requests a certificate be sent by the peer.  If presented, the certificate",
+"  is verified.  Any errors during the verification process result in",
+"  queries to the end user.  When set to FAIL-IF-NO-PEER-CERT, Kermit",
+"  requests a certificate be sent by the peer.  If the certificate is not",
+"  presented or fails to verify, the connection is terminated without",
+"  querying the user.",
+" ",
+"  If an anonymous cipher (i.e., ADH) is desired, the NO setting must be",
+"  used.  Otherwise, the receipt of the peer certificate request is",
+"  interpreted as a protocol error and the negotiation fails.",
+" ",
+"  If you wish to allow the peer to authenticate using either an X509",
+"  certificate to userid mapping function or via use of a ~/.tlslogin file",
+"  you must use either PEER-CERT or FAIL-IF-NO-PEER-CERT.  Otherwise, any",
+"  certificates that are presented is ignored.  In other words, use NO if you",
+"  want to disable the ability to use certificates to authenticate a peer.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } VERIFY-DIR <directory>",
+"  Specifies a directory that contains root CA certificate files used to",
+"  verify the certificate chains presented by the peer.  Each file is named",
+"  by a hash of the certificate.",
+" ",
+"  OpenSSL expects the hash symlinks to be made like this:",
+" ",
+"    ln -s cert.pem `openssl x509 -hash -noout -in cert.pem`.0",
+" ",
+"  Since not all file systems have symlinks you can use the following command",
+"  in Kermit to copy the cert.pem file to the hash file name.",
+" ",
+"    copy cert.pem {\\fcommand(openssl.exe x509 -hash -noout -in cert.pem).0}",
+" ",
+"  This produces a hash based on the subject field in the cert such that the",
+"  certificate may be quickly found.",
+" ",
+"SET AUTHENTICATION { SSL, TLS } VERIFY-FILE <file>",
+"  Specifies a file that contains root CA certificates to be used for",
+"  verifying certificate chains.",
+" ",
+#endif /* CK_SSL */
+""
+};
+
+static char *hxynet[] = {
+"Syntax: SET NETWORK { TYPE network-type, DIRECTORY [ file(s)... ] }",
+" ",
+"Select the type of network to be used with SET HOST connections:",
+" ",
+#ifdef NETCMD
+"  SET NETWORK TYPE COMMAND   ; Make a connection through an external command",
+#endif /* NETCMD */
+#ifdef TCPSOCKET
+"  SET NETWORK TYPE TCP/IP    ; Internet: Telnet, Rlogin, etc.",
+#endif /* TCPSOCKET */
+#ifdef ANYX25
+"  SET NETWORK TYPE X.25      ; X.25 peer-to-peer connections.",
+#endif /* ANYX25 */
+#ifdef DECNET
+"  SET NETWORK TYPE PATHWORKS { LAT, CTERM } ; DEC LAT or CTERM connections.",
+#endif /* DECNET */
+#ifdef NPIPE
+"  SET NETWORK TYPE NAMED-PIPE <pipename>  ; OS/2 Named Pipe connections.",
+#endif /* NPIPE */
+#ifdef CK_NETBIOS
+"  SET NETWORK TYPE NETBIOS                ; NETBIOS peer-to-peer connections",
+#endif /* CK_NETBIOS */
+#ifdef SUPERLAT
+"  SET NETWORK TYPE SUPERLAT ; LAT connections (Meridian Technology SuperLAT)",
+#endif /* SUPERLAT */
+" ",
+"If only one network type is listed above, that is the default network for",
+#ifdef RLOGCODE
+"SET HOST commands.  Also see SET HOST, TELNET, RLOGIN.",
+#else
+#ifdef TNCODE
+"SET HOST commands.  Also see SET HOST, TELNET.",
+#else
+"SET HOST commands.  Also see SET HOST.",
+#endif /* TNCODE */
+#endif /* RLOGCODE */
+" ",
+"SET NETWORK DIRECTORY [ file [ file [ ... ] ] ]",
+"  Specifies the name(s) of zero or more network directory files, similar to",
+"  dialing directories (HELP DIAL for details).  The general format of a",
+"  network directory entry is:",
+" ",
+"    name network-type address [ network-specific-info ] [ ; comment ]",
+" ",
+"  For TCP/IP, the format is:",
+" ",
+"    name tcp/ip ip-hostname-or-address [ socket ] [ ; comment ]",
+" ",
+"You can have multiple network directories and you can have multiple entries",
+"with the same name.  SET HOST <name> and TELNET <name> commands look up the",
+"given <name> in the directory and, if found, fill in the additional items",
+"from the entry, and then try all matching entries until one succeeds.",
+""};
+
+#ifndef NOTCPOPTS
+static char *hxytcp[] = {
+#ifdef SOL_SOCKET
+"SET TCP ADDRESS <ip-address>",
+"  This allows a specific IP Address on a multihomed host to be used",
+"  instead of allowing the TCP/IP stack to choose.  This may be necessary",
+"  when using authentication or listening for an incoming connection.",
+"  Specify no <ip-address> to remove the preference.",
+" ",
+"SET TCP KEEPALIVE { ON, OFF }",
+"  Setting this ON might help to detect broken connections more quickly.",
+"  (default is ON.)",
+" ",
+"SET TCP LINGER { ON [timeout], OFF }",
+"  Setting this ON ensures that a connection doesn't close before all",
+"  outstanding data has been transferred and acknowledged.  The timeout is",
+"  measured in 10ths of milliseconds.  The default is ON with a timeout of 0.",
+" ",
+"SET TCP NODELAY { ON, OFF }",
+"  ON means send short TCP packets immediately rather than waiting",
+"  to accumulate a bunch of them before transmitting (Nagle Algorithm).",
+"  (default is OFF.)",
+" ",
+"SET TCP RECVBUF <number>",
+"SET TCP SENDBUF <number>",
+"   TCP receive and send buffer sizes.  (default is -1, use system defaults.)",
+" ",
+"These items let you tune TCP networking performance on a per-connection",
+"basis by adjusting parameters you normally would not have access to.  You",
+"should use these commands only if you feel that the TCP/IP protocol stack",
+"that Kermit is using is giving you inadequate performance, and then only if",
+"you understand the concepts (see, for example, the Comer TCP/IP books), and",
+"then at your own risk.  These settings are displayed by SHOW NETWORK.  Not",
+"all options are necessarily available in all Kermit versions; it depends on",
+"the underlying TCP/IP services.",
+" ",
+"The following TCP and/or IP parameter(s) may also be changed:",
+" ",
+#endif /* SOL_SOCKET */
+"SET TCP REVERSE-DNS-LOOKUP { AUTO, ON, OFF }",
+"  Tells Kermit whether to perform reverse DNS lookup on TCP/IP connections",
+"  so Kermit can determine the actual hostname of the host it is connected",
+"  to, which is useful for connections to host pools, and is required for",
+"  Kerberos connections to host pools and for incoming connections.  If the",
+"  other host does not have a DNS entry, the reverse lookup could take a long",
+"  time (minutes) to fail, but the connection will still be made.  Turn this",
+"  option OFF for speedier connections if you do not need to know exactly",
+"  which host you are connected to and you are not using Kerberos.  AUTO, the",
+"  default, means the lookup is done on hostnames, but not on numeric IP",
+"  addresses unless Kerberos support is installed.",
+#ifdef CK_DNS_SRV
+" ",
+"SET TCP DNS-SERVICE-RECORDS {ON, OFF}",
+"  Tells Kermit whether to try to use DNS SRV records to determine the",
+"  host and port number upon which to find an advertised service.  For",
+"  example, if a host wants regular Telnet connections redirected to some",
+"  port other than 23, this feature allows Kermit to ask the host which",
+"  port it should use.  Since not all domain servers are set up to answer",
+"  such requests, this feature is OFF by default.",
+#endif /* CK_DNS_SRV */
+#ifdef NT
+#ifdef CK_SOCKS
+" ",
+"SET TCP SOCKS-SERVER [<hostname or ip-address>]",
+"  If a hostname or ip-address is specified, Kermit will use the SOCKS",
+"  server when attempting outgoing connections.  If no hostname or",
+"  ip-address is specified, any previously specified SOCKS server will",
+"  be removed.",
+#endif /* CK_SOCKS */
+#endif /* NT */
+#ifndef NOHTTP
+" ",
+"SET TCP HTTP-PROXY [<hostname or ip-address>[:<port>]]",
+"  If a hostname or ip-address is specified, Kermit will use the Proxy",
+"  server when attempting outgoing connections.  If no hostname or",
+"  ip-address is specified, any previously specified Proxy server will",
+"  be removed.  If no port number is specified, the \"http\" service",
+"  will be used.",
+#endif /* NOHTTP */
+""};
+#endif /* NOTCPOPTS */
+#endif /* NETCONN */
+
+#ifdef TNCODE
+static char *hxytopt[] = {
+"SET TELOPT [ { /CLIENT, /SERVER } ] <option> -",
+"    { ACCEPTED, REFUSED, REQUESTED, REQUIRED } -",
+"    [ { ACCEPTED, REFUSED, REQUESTED, REQUIRED } ]",
+"  SET TELOPT lets you specify policy requirements for Kermit's handling of",
+"  Telnet option negotiations.  Setting an option REQUIRED causes Kermit",
+"  to offer the option to the peer and disconnect if the option is refused.",
+"  REQUESTED causes Kermit to offer an option to the peer.  ACCEPTED results",
+"  in no offer but Kermit will attempt to negotiate the option if it is",
+"  requested.  REFUSED instructs Kermit to refuse the option if it is",
+"  requested by the peer.",
+" ",
+"  Some options are negotiated in two directions and accept separate policies",
+"  for each direction; the first keyword applies to Kermit itself, the second",
+"  applies to Kermit's Telnet partner; if the second keyword is omitted, an",
+"  appropriate (option-specific) default is applied.  You can also include a",
+"  /CLIENT or /SERVER switch to indicate whether the given policies apply",
+"  when Kermit is the Telnet client or the Telnet server; if no switch is",
+"  given, the command applies to the client.",
+" ",
+"  Note that some of Kermit's Telnet partners fail to refuse options that",
+"  they do not recognize and instead do not respond at all.  In this case it",
+"  is possible to use SET TELOPT to instruct Kermit to REFUSE the option",
+"  before connecting to the problem host, thus skipping the problematic",
+"  negotiation.",
+" ",
+"  Use SHOW TELOPT to view current Telnet Option negotiation settings.",
+"  SHOW TELNET displays current Telnet settings.",
+""};
+
+static char *hxytel[] = {
+"Syntax: SET TELNET parameter value",
+" ",
+"For TCP/IP TELNET connections, which are in NVT (ASCII) mode by default:",
+" ",
+#ifdef CK_AUTHENTICATION
+#ifdef COMMENT
+"SET TELNET AUTHENICATION { ACCEPTED, REFUSED, REQUESTED, REQUIRED }",
+"  ACCEPT or REFUSE authentication bids, or actively REQUEST authentication.",
+"  REQUIRED refuses the connection if authentication is not successfully",
+"  negotiated.  ACCEPTED by default.",
+" ",
+#endif /* COMMENT */
+"SET TELNET AUTHENTICATION TYPE { AUTOMATIC, KERBEROS_IV, KERBEROS_V, ...",
+#ifdef NT
+"  ..., NTLM, SSL, SRP, NONE } [...]",
+#else /* NT */
+"  ..., SSL, SRP, NONE } [...]",
+#endif /* NT */
+"  AUTOMATIC is the default.  Available options can vary depending on the",
+"  features Kermit was built to support and the operating system",
+"  configuration; type SET TELNET AUTHENTICATION TYPE ? for a list.",
+" ",
+"  When Kermit is the Telnet client:",
+"    AUTOMATIC allows the host to choose the preferred type of authentication."
+,
+"    NONE instructs Kermit to refuse all authentication methods when the",
+"    authentication option is negotiated.  A list of one or more other values",
+"    allow a specific subset of the supported authentication methods to be",
+"    used.",
+" ",
+"  When Kermit is the Telnet server:",
+"    AUTOMATIC results in available authentication methods being offered",
+"    to the telnet client in the following order:",
+" ",
+#ifdef NT
+"      KERBEROS_V, KERBEROS_IV, SRP, SSL, NTLM",
+#else /* NT */
+"      KERBEROS_V, KERBEROS_IV, SRP, SSL, NTLM",
+#endif /* NT */
+" ",
+"  NONE results in no authentication methods being offered to the Telnet",
+"  server when the authentication option is negotiated.  The preferred",
+"  method of disabling authentication is:",
+" ",
+"    SET TELOPT /SERVER AUTHENTICATION REFUSE",
+" ",
+"  A list of one or more authentication methods specifies the order those",
+"  methods are to be offered to the telnet client.",
+#ifdef NT
+" ",
+"  If you wish to allow NTLM authentication to be used with the Microsoft",
+"  Windows 2000 or Services for Unix Telnet client you must specify a list",
+"  with NTLM as the first item in the list.  By default, NTLM is the last",
+"  item in the list because it does not provide any form of data encryption.",
+#endif /* NT */
+" ",
+#ifdef CK_KERBEROS
+"SET TELNET AUTHENTICATION FORWARDING { ON, OFF }",
+"  Set this to ON to forward Kerberos V ticket-granting-tickets to the host",
+"  after authentication is complete.  OFF by default.",
+" ",
+#endif /* CK_KERBEROS */
+"SET TELNET AUTHENTICATION ENCRYPT-FLAG { ANY, NONE, TELOPT }",
+"  Use this command to specify which AUTH telopt encryption flags may be",
+"  accepted in client mode or offered in server mode.  The default is ANY.",
+" ",
+"SET TELNET AUTHENTICATION HOW-FLAG { ANY, ONE-WAY, MUTUAL }",
+"  Use this command to specify which AUTH telopt how flags may be",
+"  accepted in client mode or offered in server mode.  The default is ANY.",
+" ",
+#endif /* CK_AUTHENTICATION */
+#ifdef COMMENT
+"SET TELNET BINARY-MODE { ACCEPTED, REFUSED, REQUESTED, REQUIRED }",
+"  ACCEPT or REFUSE binary-mode bids, or actively REQUEST binary mode.",
+"  REQUIRED refuses the connection if binary mode is not successfully",
+"  negotiated in both directions.  ACCEPTED by default.",
+" ",
+#endif /* COMMENT */
+"SET TELNET BINARY-TRANSFER-MODE { ON, OFF }",
+"  When ON (OFF by default) and BINARY negotiations are not REFUSED Kermit",
+"  will attempt to negotiate BINARY mode in each direction before the start",
+"  of each file transfer.  After the transfer is complete BINARY mode will",
+"  be restored to the pre-transfer state.",
+" ",
+"SET TELNET BINARY-TRANSFER-MODE { ON, OFF }",
+"  Set this command to ON if you want to force Kermit to negotiate",
+"  Telnet Binary in both directions when performing file transfers.",
+"  Default is OFF.  Alias SET TELNET BINARY-XFER-MODE.",
+" ",
+"SET TELNET BUG AUTH-KRB5-DES { ON, OFF }",
+"  Default is ON.  Disable this bug to enable the use of encryption types",
+"  other than DES such as 3DES or CAST-128 when the Kerberos 5 session key",
+"  is longer than 8 bytes.",
+" ",
+"SET TELNET BUG BINARY-ME-MEANS-U-TOO { ON, OFF }",
+"  Set this to ON to try to overcome TELNET binary-mode misnegotiations by",
+"  Kermit's TELNET partner.",
+" ",
+"SET TELNET BUG BINARY-U-MEANS-ME-TOO { ON, OFF }",
+"  Set this to ON to try to overcome TELNET binary-mode misnegotiations by",
+"  Kermit's TELNET partner.",
+" ",
+"SET TELNET BUG INFINITE-LOOP-CHECK { ON, OFF }",
+"  Set this to ON to prevent Kermit from responding to a telnet negotiation",
+"  sequence that enters an infinite loop.  The default is OFF because this",
+"  should never occur.",
+" ",
+"SET TELNET BUG SB-IMPLIES-WILL-DO { ON, OFF }",
+"  Set this to ON to allow Kermit to respond to telnet sub-negotiations if",
+"  the peer forgets to respond to WILL with DO or to DO with WILL.",
+" ",
+"SET TELNET DEBUG { ON, OFF }",
+"  Set this to ON to display telnet negotiations as they are sent and",
+"  received.",
+" ",
+"SET TELNET DELAY-SB { ON, OFF }",
+"  When ON, telnet subnegotiation responses are delayed until after all",
+"  authentication and encryption options are either successfully negotiated",
+"  or refused. This ensures that private data is protected.  When OFF, telnet",
+"  subnegotiation responses are sent immediately.  The default is ON.",
+" ",
+"SET TELNET ECHO { LOCAL, REMOTE }",
+"  Kermit's initial echoing state for TELNET connections, LOCAL by default.",
+"  After the connection is made, TELNET negotiations determine the echoing.",
+" ",
+#ifdef CK_ENCRYPTION
+#ifdef COMMENT
+"SET TELNET ENCRYPTION { ACCEPTED, REFUSED, REQUESTED, REQUIRED }",
+"  ACCEPT or REFUSE encryption bids, or actively REQUEST encryption in both.",
+"  directions.  REQUIRED refuses the connection if encryption is not",
+"  successfully negotiated in both directions.  ACCEPTED by default.",
+" ",
+#endif /* COMMENT */
+"SET TELNET ENCRYPTION TYPE { AUTOMATIC, CAST128_CFB64, CAST128_OFB64, ",
+"  CAST5_40_CFB64, CAST5_40_OFB64, DES_CFB64, DES_OFB64, NONE }",
+"  AUTOMATIC allows the host to choose the preferred type of encryption.",
+"  Other values allow a specific encryption method to be specified.",
+"  AUTOMATIC is the default.  The list of options will vary depending",
+"  on the encryption types selected at compilation time.",
+" ",
+#endif /* CK_ENCRYPTION */
+#ifdef CK_ENVIRONMENT
+#ifdef COMMENT
+"SET TELNET ENVIRONMENT { ON, OFF, variable-name [ value ] }",
+"  This feature lets Kermit send the values of certain environment variables",
+"  to the other computer if it asks for them.  The variable-name can be any",
+"  of the \"well-known\" variables \"USER\", \"JOB\", \"ACCT\", \"PRINTER\",",
+"  \"SYSTEMTYPE\", or \"DISPLAY\".  Some Telnet servers, if given a USER",
+"  value in this way, will accept it and therefore not prompt you for user",
+"  name when you log in.  The default values are taken from your environment;",
+"  use this command to change or remove them.  See RFC1572 for details.  You",
+"  may also specify OFF to disable this feature, and ON to re-enable it.",
+" ",
+#else
+"SET TELNET ENVIRONMENT { variable-name [ value ] }",
+"  This feature lets Kermit send the values of certain environment variables",
+"  to the other computer if it asks for them.  The variable-name can be any",
+"  of the \"well-known\" variables \"USER\", \"JOB\", \"ACCT\", \"PRINTER\",",
+"  \"SYSTEMTYPE\", or \"DISPLAY\".  Some Telnet servers, if given a USER",
+"  value in this way, will accept it and therefore not prompt you for user",
+"  name when you log in.  The default values are taken from your environment;",
+"  use this command to change or remove them.  See RFC1572 for details.",
+" ",
+#endif /* COMMENT */
+#endif /* CK_ENVIRONMENT */
+#ifdef CK_FORWARD_X
+"SET TELNET FORWARD-X XAUTHORITY-FILE <file>",
+"  If your X Server requires X authentication and the location of the",
+"  .Xauthority file is not defined by the XAUTHORITY environment variable,",
+"  use this command to specify the location of the .Xauthority file."
+"  ",
+#endif /* CK_FORWARD_X */
+#ifdef CK_SNDLOC
+"SET TELNET LOCATION [ text ]",
+"  Location string to send to the Telnet server if it asks.  By default this",
+"  is picked up from the LOCATION environment variable.  Give this command",
+"  with no text to disable this feature.",
+" ",
+#endif /* CK_SNDLOC */
+"SET TELNET NEWLINE-MODE { NVT, BINARY-MODE } { OFF, ON, RAW }",
+
+"  Determines how carriage returns are handled on TELNET connections.  There",
+"  are separate settings for NVT (ASCII) mode and binary mode.  ON (default",
+"  for NVT mode) means CRLF represents CR.  OFF means CR followed by NUL",
+"  represents CR.  RAW (default for BINARY mode) means CR stands for itself.",
+" ",
+#ifdef TCPSOCKET
+"SET TELNET PROMPT-FOR-USERID <prompt>",
+"  Specifies a custom prompt to be used when prompting for a userid.  Kermit",
+"  prompts for a userid if the command:",
+" ",
+"    SET LOGIN USERID {}",
+" ",
+"  has been issued prior to a Telnet authentication negotiation for an",
+"  authentication type that requires the transmission of a name, such as",
+"  Secure Remote Password.",
+" ",
+#endif /* TCPSOCKET */
+"SET TELNET REMOTE-ECHO { ON, OFF }",
+"  Applies only to incoming connections created with:",
+"    SET HOST * <port> /TELNET",
+"  This command determines whether Kermit will actually echo characters",
+"  received from the remote when it has negotiated to do so.  The default",
+"  is ON.  Remote echoing may be turned off when it is necessary to read",
+"  a password with the INPUT command.",
+" ",
+"SET TELNET TERMINAL-TYPE name",
+"  The terminal type to send to the remote TELNET host.  If none is given,",
+#ifdef OS2
+"  your current SET TERMINAL TYPE value is sent, e.g. VT220.",
+" ",
+#else
+"  your local terminal type is sent.",
+" ",
+#endif /* OS2 */
+"SET TELNET WAIT-FOR-NEGOTIATIONS { ON, OFF }",
+"  Each Telnet option must be fully negotiated either On or Off before the",
+"  session can continue.  This is especially true with options that require",
+"  subnegotiations such as Authentication, Encryption, and Kermit; for",
+"  proper support of these options Kermit must wait for the negotiations to",
+"  complete.  Of course, Kermit has no way of knowing whether a reply is",
+"  delayed or not coming at all, and so will wait a minute or more for",
+"  required replies before continuing the session.  If you know that Kermit's",
+"  Telnet partner will not be sending the required replies, you can set this",
+"  option of OFF to avoid the long timeouts.  Or you can instruct Kermit to",
+"  REFUSE specific options with the SET TELOPT command.",
+"",
+"Type SHOW TELNET to see the current values of these parameters.",
+"" };
+#endif /* TNCODE */
+
+#ifndef NOSPL
+static char *hxymacr[] = {
+"Syntax: SET MACRO parameter value",
+"  Controls the behavior of macros.",
+" ",
+"SET MACRO ECHO { ON, OFF }",
+"  Tells whether commands executed from a macro definition should be",
+"  displayed on the screen.  OFF by default; use ON for debugging.",
+" ",
+"SET MACRO ERROR { ON, OFF }",
+"  Tells whether a macro should be automatically terminated upon a command",
+"  error.  This setting is local to the current macro, and inherited by",
+"  subordinate macros.",
+"" };
+#endif /* NOSPL */
+
+static char *hmxyprm[] = {
+"Syntax: SET PROMPT [ text ]",
+" ",
+#ifdef OS2
+"Prompt text for this program, normally 'K-95>'.  May contain backslash",
+#else
+#ifdef MAC
+"Prompt text for this program, normally 'Mac-Kermit>'.  May contain backslash",
+#else
+"Prompt text for this program, normally 'C-Kermit>'.  May contain backslash",
+#endif /* MAC */
+#endif /* OS2 */
+"codes for special effects.  Surround by { } to preserve leading or trailing",
+#ifdef OS2
+"spaces.  If text omitted, prompt reverts to K-95>.  Prompt can include",
+#else
+#ifdef MAC
+"spaces.  If text omitted, prompt reverts to Mac-Kermit>.  Prompt can include",
+#else
+"spaces.  If text omitted, prompt reverts to C-Kermit>.  Prompt can include",
+#endif /* OS2 */
+#endif /* MAC */
+"variables like \\v(dir) or \\v(time) to show current directory or time.",
+"" };
+
+#ifdef UNIX
+static char *hxywild[] = {
+"Syntax: SET WILDCARD-EXPANSION { KERMIT [ switch ], SHELL }",
+"  KERMIT (the default) means C-Kermit expands filename wildcards in SEND and",
+"  similar commands itself, and in incoming GET commands.  Optional switches",
+"  are /NO-MATCH-DOT-FILES (\"*\" and \"?\" should not match in initial",
+"  period in a filename; this is the default) and /MATCH-DOT-FILES if you",
+"  want files whose names begin with \".\" included.  SET WILDCARD SHELL",
+"  means that Kermit asks your preferred shell to expand wildcards (this",
+"  should not be necessary in C-Kermit 7.0 and later).  HELP WILDCARD for",
+"  further information.",
+"" };
+#endif /* UNIX */
+
+#ifndef NOXFER
+static char *hxywind[] = {
+"Syntax: SET WINDOW-SIZE number",
+"  Specifies number of slots for sliding windows, i.e. the number of packets",
+"  that can be transmitted before waiting for acknowledgement.  The default",
+#ifdef XYZ_INTERNAL
+"  for Kermit protocol is one, the maximum is 32; for ZMODEM, the default",
+"  is no windowing (0).  For ZMODEM, the window size is really the packet",
+"  length, and is used only when non-windowed (streaming) transfers fail; the",
+"  ZMODEM window size should be a largish number, like 1024, and it should be",
+"  a multiple of 64.",
+#else
+"  is one, the maximum is 32.  Increased window size might result in reduced",
+"  maximum packet length.  Use sliding windows for improved efficiency on",
+"  connections with long delays.  A full duplex connection is required, as",
+"  well as a cooperating Kermit on the other end.",
+#endif /* XYZ_INTERNAL */
+"" };
+
+static char *hxyrpt[] = {
+"Syntax: SET REPEAT { COUNTS { ON, OFF }, PREFIX <code> }",
+"  SET REPEAT COUNTS turns the repeat-count compression mechanism ON and OFF.",
+"  The default is ON.  SET REPEAT PREFIX <code> sets the repeat-count prefix",
+"  character to the given code.  The default is 126 (tilde).",
+"" };
+
+static char *hxyrcv[] = {
+"Syntax: SET RECEIVE parameter value",
+"  Specifies parameters for inbound packets:",
+" ",
+#ifndef NOCSETS
+"SET RECEIVE CHARACTER-SET { AUTOMATIC, MANUAL }",
+"  Whether to automatically switch to an appropriate file-character set based",
+"  on the transfer character-set announcer, if any, of an incoming text file.",
+"  AUTOMATIC by default.  Also see HELP ASSOCIATE.",
+" ",
+#endif /* NOCSETS */
+"SET RECEIVE CONTROL-PREFIX number",
+"  ASCII value of prefix character used for quoting control characters in",
+"  packets that Kermit receives, normally 35 (number sign).  Don't change",
+"  this unless something is wrong with the other Kermit program.",
+" ",
+"SET RECEIVE END-OF-PACKET number",
+"  ASCII value of control character that terminates incoming packets,",
+"  normally 13 (carriage return).",
+" ",
+#ifdef CKXXCHAR
+"SET RECEIVE IGNORE-CHARACTER number",
+"  ASCII value of character to be discarded when receiving packets, such as",
+"  line folding characters.",
+" ",
+#endif /* CKXXCHAR */
+"SET RECEIVE MOVE-TO [ directory ]",
+"  If a directory name is specified, then every file that is received",
+"  successfully is moved to the given directory immediately after reception",
+"  is complete.  Omit the directory name to remove any previously set move-to",
+"  directory.",
+" ",
+"SET RECEIVE PACKET-LENGTH number",
+"  Maximum length packet the other Kermit should send.",
+" ",
+"SET RECEIVE PADDING number",
+"  Number of prepacket padding characters to ask for (normally 0).",
+" ",
+"SET RECEIVE PAD-CHARACTER number",
+"  ASCII value of control character to use for padding (normally 0).",
+" ",
+"SET RECEIVE PATHNAMES {OFF, ABSOLUTE, RELATIVE, AUTO}",
+"  If a recognizable path (directory, device) specification appears in an",
+"  incoming filename, strip it OFF before trying to create the output file.",
+#ifdef CK_MKDIR
+"  Otherwise, then if any of the directories in the path don't exist, Kermit",
+"  tries to create them, relative to your current or download directory, or",
+"  absolutely, as specified.  RELATIVE means force all incoming names, even",
+"  if they are absolute, to be relative to your current or download directory."
+,
+"  AUTO, which is the default, means RELATIVE if the file sender indicates in",
+"  advance that this is a recursive transfer, otherwise OFF.",
+#endif /* CK_MKDIR */
+" ",
+"SET RECEIVE PAUSE number",
+"  Milliseconds to pause between packets, normally 0.",
+" ",
+
+#ifdef CK_PERMS
+"SET RECEIVE PERMISSIONS { ON, OFF }",
+"  Whether to copy file permissions from inbound Attribute packets.",
+" ",
+#endif /* CK_PERMS */
+
+"SET RECEIVE RENAME-TO [ template ]",
+"  If a template is specified, then every file that is received successfully",
+"  \
+is renamed according to the given template immediately after it is received.",
+"  \
+The template should include variables like \\v(filename) or \\v(filenumber).",
+"  Omit the template to remove any template previously set.",
+" ",
+"SET RECEIVE START-OF-PACKET number",
+"  ASCII value of character that marks start of inbound packet.",
+" ",
+"SET RECEIVE TIMEOUT number",
+"  Number of seconds the other Kermit should wait for a packet before sending",
+"  a NAK or retransmitting.",
+#ifdef VMS
+" ",
+"SET RECEIVE VERSION-NUMBERS { ON, OFF }",
+"  If ON, and in incoming filename includes a VMS version number, use it when",
+"  creating the file.  If OFF (which is the default), strip any VMS version",
+"  number from incoming filenames before attempting to create the file, \
+causing",
+"  the new file to receive the next highest version number.",
+#endif /* VMS */
+"" };
+
+static char *hxysnd[] = {
+"Syntax: SET SEND parameter value",
+"  Specifies parameters for outbound files or packets.",
+" ",
+"SET SEND BACKUP { ON, OFF }",
+"  Tells whether to include backup files when sending file groups.  Backup",
+"  files are those created by Kermit, EMACS, etc, when creating a new file",
+"  that has the same name as an existing file.  A backup file has a version",
+"  appended to its name, e.g. oofa.txt.~23~.  ON is the default, meaning",
+"  don't exclude backup files.  Use OFF to exclude backup files from group",
+"  transfers.",
+" ",
+#ifndef NOCSETS
+"SET SEND CHARACTER-SET { AUTOMATIC, MANUAL }",
+"  Whether to automatically switch to an appropriate file-character when a",
+"  SET TRANSFER CHARACTER-SET command is given, or vice versa.  AUTOMATIC by",
+"  default.  Also see HELP ASSOCIATE.",
+" ",
+#endif /* NOCSETS */
+
+"SET SEND CONTROL-PREFIX number",
+"  ASCII value of prefix character used for quoting control characters in",
+"  packets that Kermit sends, normally 35 (number sign).",
+" ",
+#ifdef CKXXCHAR
+"SET SEND DOUBLE-CHARACTER number",
+"  ASCII value of character to be doubled when sending packets, such as an",
+"  X.25 PAD escape character.",
+" ",
+#endif /* CKXXCHAR */
+"SET SEND END-OF-PACKET number",
+"  ASCII value of control character to terminate an outbound packet,",
+"  normally 13 (carriage return).",
+" ",
+"SET SEND MOVE-TO [ directory ]",
+"  \
+If a directory name is specified, then every file that is sent successfully",
+"  is moved to the given directory immediately after it is sent.",
+"  Omit the directory name to remove any previously set move-to directory.",
+" ",
+"SET SEND PACKET-LENGTH number",
+"  Maximum length packet to send, even if other Kermit asks for longer ones.",
+"  This command can not be used to force packets to be sent that are longer",
+"  than the length requested by the receiver.  Use this command only to",
+"  force shorter ones.",
+" ",
+"SET SEND PADDING number",
+"  Number of prepacket padding characters to send.",
+" ",
+"SET SEND PAD-CHARACTER number",
+"  ASCII value of control character to use for padding.",
+" ",
+"SET SEND PATHNAMES {OFF, ABSOLUTE, RELATIVE}",
+"  Include the path (device, directory) portion with the file name when",
+"  sending it as specified; ABSOLUTE means to send the whole pathname,",
+"  RELATIVE means to include the pathname relative to the current directory.",
+"  Applies to the actual filename, not to the \"as-name\".  The default is",
+"  OFF.",
+" ",
+"SET SEND PAUSE number",
+"  Milliseconds to pause between packets, normally 0.",
+" ",
+
+#ifdef CK_PERMS
+"SET SEND PERMISSIONS { ON, OFF }",
+"  Whether to include file permissions in outbound Attribute packets.",
+" ",
+#endif /* CK_PERMS */
+
+"SET SEND RENAME-TO [ template ]",
+"  If a template is specified, then every file that is sent successfully",
+"  is renamed according to the given template immediately after it is sent.",
+"  \
+The template should include variables like \\v(filename) or \\v(filenumber).",
+"  Omit the template to remove any template previously set.",
+" ",
+"SET SEND START-OF-PACKET number",
+"  ASCII value of character to mark start of outbound packet.",
+" ",
+#ifdef CK_TIMERS
+"SET SEND TIMEOUT number [ { DYNAMIC [ min max ] ], FIXED } ]",
+#else
+"SET SEND TIMEOUT number",
+#endif /* CK_TIMERS */
+
+"  Number of seconds to wait for a packet before sending NAK or",
+#ifdef CK_TIMERS
+"  retransmitting.  Include the word DYNAMIC after the number in the",
+"  SET SEND TIMEOUT command to have Kermit compute the timeouts dynamically",
+"  throughout the transfer based on the packet rate.  Include the word FIXED",
+"  to use the \"number\" given throughout the transfer.  DYNAMIC is the",
+"  default.  After DYNAMIC you may include minimum and maximum values.",
+#else
+"  retransmitting.",
+#endif /* CK_TIMERS */
+#ifdef VMS
+" ",
+"SET SEND VERSION-NUMBERS { ON, OFF }",
+"  If ON, include VMS version numbers in outbound filenames.  If OFF (which",
+"  is the default), strip version numbers.",
+#endif /* VMS */
+"" };
+
+static char *hxyxfer[] = {
+"Syntax: SET TRANSFER (or XFER) paramater value",
+" ",
+"Choices:",
+" ",
+"SET TRANSFER BELL { OFF, ON }",
+"  Whether to ring the terminal bell at the end of a file transfer.",
+" ",
+#ifdef XFRCAN
+"SET TRANSFER CANCELLATION { OFF, ON [ <code> [ <number> ] ] }",
+"  OFF disables remote-mode packet-mode cancellation from the keyboard.",
+"  ON enables it.  The optional <code> is the control character to use for",
+"  cancellation; the optional <number> is how many consecutive occurrences",
+"  of the given control character are required for cancellation.",
+" ",
+#endif /* XFRCAN */
+"SET TRANSFER INTERRUPTION { ON, OFF }",
+"  TRANSFER INTERRUPTION is normally ON, allowing for interruption of a file",
+"  transfer in progress by typing certain characters while the file-transfer",
+"  display is active.  SET TRANSFER INTERRUPTION OFF disables interruption",
+"  of file transfer from the keyboard in local mode.",
+" ",
+#ifndef NOSPL
+"SET TRANSFER CRC-CALCULATION { OFF, ON }",
+"  Tells whether Kermit should accumulate a Cyclic Redundancy Check for ",
+"  each file transfer.  Normally ON, in which case the CRC value is available",
+"  in the \\v(crc16) variable after the transfer.  Adds some overhead.  Use",
+"  SET TRANSFER CRC OFF to disable.",
+" ",
+#endif /* NOSPL */
+#ifndef NOCSETS
+"SET TRANSFER CHARACTER-SET name",
+"  Selects the character set used to represent textual data in Kermit",
+"  packets.  Text characters are translated to/from the FILE CHARACTER-SET.",
+"  Choices:",
+" ",
+"  TRANSPARENT (no translation, the default)",
+"  ASCII",
+"  LATIN1 (ISO 8859-1 Latin Alphabet 1)",
+#ifndef NOLATIN2
+"  LATIN2 (ISO 8859-2 Latin Alphabet 2)",
+#endif /* NOLATIN2 */
+"  LATIN9 (ISO 8859-15 Latin Alphabet 9)",
+#ifdef CYRILLIC
+"  CYRILLIC-ISO (ISO 8859-5 Latin/Cyrillic)",
+#endif /* CYRILLIC */
+#ifdef GREEK
+"  GREEK-ISO (ISO 8859-7 Latin/Greek)",
+#endif /* GREEK */
+#ifdef HEBREW
+"  HEBREW-ISO (ISO 8859-8 Latin/Hebrew)",
+#endif /* HEBREW */
+#ifdef KANJI
+"  JAPANESE-EUC (JIS X 0208 Kanji + Roman and Katakana)",
+#endif /* KANJI */
+#ifdef UNICODE
+"  UCS-2 (ISO 10646 / Unicode 2-byte form)",
+"  UTF-8 (ISO 10646 / Unicode 8-bit serialized transformation format)",
+#endif /* UNICODE */
+" ",
+"SET TRANSFER TRANSLATION { ON, OFF }",
+"  Enables and disables file-transfer character-set translation.  It's",
+"  enabled by default.",
+#endif /* NOCSETS */
+" ",
+#ifdef CK_CURSES
+"SET TRANSFER DISPLAY { BRIEF, CRT, FULLSCREEN, NONE, SERIAL }",
+#else
+"SET TRANSFER DISPLAY { BRIEF, CRT, NONE, SERIAL }",
+#endif  /* CK_CURSES */
+"  Choose the desired format for the progress report to be displayed on",
+"  your screen during file transfers when Kermit is in local mode.",
+#ifdef CK_CURSES
+"  FULLSCREEN requires your terminal type be set correctly; the others",
+"  are independent of terminal type.",
+#else
+"  file transfer.",
+#endif  /* CK_CURSES */
+" ",
+"SET TRANSFER LOCKING-SHIFT { OFF, ON, FORCED }",
+"  Tell whether locking-shift protocol should be used during file transfer",
+"  to achieve 8-bit transparency on a 7-bit connection.  ON means to request",
+"  its use if PARITY is not NONE and to use it if the other Kermit agrees,",
+"  OFF means not to use it, FORCED means to use it even if the other Kermit",
+"  does not agree.",
+" ",
+"SET TRANSFER MODE { AUTOMATIC, MANUAL }",
+"  Automatic (the default) means Kermit should automatically go into binary",
+"  file-transfer mode and use literal filenames if the other Kermit says it",
+"  has a compatible file system, e.g. UNIX-to-UNIX, but not UNIX-to-DOS.",
+#ifdef PATTERNS
+"  Also, when sending files, Kermit should switch between binary and text",
+"  mode automatically per file based on the SET FILE BINARY-PATTERNS and SET",
+"  FILE TEXT-PATTERNS.",
+#endif /* PATTERNS */
+" ",
+#ifdef PIPESEND
+"SET TRANSFER PIPES { ON, OFF }",
+"  Enables/Disables automatic sending from / reception to command pipes when",
+"  the incoming filename starts with '!'.  Also see CSEND, CRECEIVE.",
+" ",
+#endif /* PIPESEND */
+#ifdef CK_XYZ
+"SET TRANSFER PROTOCOL { KERMIT, XMODEM, ... }",
+"  Synonym for SET PROTOCOL (q.v.).",
+" ",
+#endif /* CK_XYZ */
+"SET TRANSFER REPORT { ON, OFF }",
+"  Enables/Disables the automatic post-transfer message telling what files",
+"  went where from C-Kermit when it is in remote mode.  ON by default.",
+" ",
+"SET TRANSFER SLOW-START { OFF, ON }",
+"  ON (the default) tells Kermit, when sending files, to gradually build up",
+"  the packet length to the maximum negotiated length.  OFF means start",
+"  sending the maximum length right away.",
+" ",
+"Synonym: SET XFER.  Use SHOW TRANSFER (XFER) to see SET TRANSFER values.",
+"" };
+#endif /* NOXFER */
+
+#ifdef NT
+static char *hxywin95[] = {
+"SET WIN95 8.3-FILENAMES { ON, OFF }",
+"  Instructs K-95 to report all filenames using 8.3 notation instead of the",
+"  normal long filenames.  Default is OFF",
+" ",
+"SET WIN95 ALT-GR { ON, OFF }",
+"  Instructs K-95, when used on MS Windows 95, to interpret the Right Alt key",
+"  as the Alt-Gr key.  This is necessary to work around the failure of",
+"  Windows 95 to properly translate non-US keyboards.  Default is OFF.",
+" ",
+"SET WIN95 KEYBOARD-TRANSLATION <character-set>",
+"  Specifies the character-set that Windows 95 is using to send keystrokes",
+"  to Kermit-95 via the keyboard input functions.  Default is Latin1-ISO.",
+" ",
+"SET WIN95 OVERLAPPED-IO { ON <requests>, OFF }",
+"  Determines whether or not K-95 uses Overlapped-I/O methods for reading",
+"  from and writing to serial and TAPI communication devices.  <requests>",
+"  specifies the maximum number of simultaneous write requests that may be",
+"  overlapped, from 1 to 30.  Default is ON.",
+" ",
+"SET WIN95 POPUPS { ON, OFF }",
+"  Determines whether or not Kermit 95 uses Popups to query the user for",
+"  necessary information such as user IDs or passwords.  Default is ON.",
+" ",
+"SET WIN95 SELECT-BUG { ON, OFF }"
+"  Some TCP/IP (Winsock) implementations for Windows have a defective",
+"  select() function.  Use this command to avoid the use of select() if",
+"  K95 appears to be unable to send data over TCP/IP.  Default is OFF.",
+""};
+#endif /* NT */
+
+static char *hmxybel[] = {
+#ifdef OS2
+"Syntax: SET BELL { AUDIBLE [ { BEEP, SYSTEM-SOUNDS } ], VISIBLE, NONE }",
+"  Specifies how incoming Ctrl-G (bell) characters are handled in CONNECT",
+"  mode and how command warnings are presented in command mode.  AUDIBLE",
+"  means either a beep or a system-sound is generated; VISIBLE means the",
+"  screen is flashed momentarily.",
+#else
+"Syntax: SET BELL { OFF, ON }",
+"  ON (the default) enables ringing of the terminal bell (beep) except where",
+"  it is disabled in certain circumstances, e.g. by SET TRANSFER BELL.  OFF",
+"  disables ringing of the bell in all circumstances, overriding any specific",
+"  SET xxx BELL selections.",
+#endif /* OS2 */
+""};
+
+static char *hmxycd[] = {
+"Syntax: SET CD { HOME <path>, PATH <path>, MESSAGE { ON, OFF, FILE <list> } }"
+,
+" ",
+"SET CD HOME <path>",
+"  Specified which directory to change to if CD or KCD is given without a",
+"  pathname.  If this command is not given, your login or HOME directory is",
+"  used.",
+" ",
+"SET CD PATH <path>",
+"  Overrides normal CDPATH environment variable, which tells the CD command",
+"  where to look for directories to CD to if you don't specify them fully.",
+"  The format is:",
+" ",
+#ifdef UNIXOROSK
+"    set cd path :directory:directory:...",
+" ",
+"  in other words, a list of directories separated by colons, with a colon",
+"  at the beginning, e.g.:",
+" ",
+"    set cd path :/usr/olga:/usr/ivan/public:/tmp",
+#else
+#ifdef OS2
+"    set cd path disk:directory;disk:directory;...",
+" ",
+"  just like the DOS PATH; in other words, a list of disk:directory names",
+"  separated by semicolons, e.g.:",
+" ",
+"    SET CD PATH C:\\K95;C:\\HOME;C:\\LOCAL;C:\\",
+#else
+#ifdef VMS
+"    set cd path directory,directory,...",
+" ",
+"  in other words, a list of directory specifications or logical names that",
+"  represent them, e.g.:",
+" ",
+"    SET CD PATH SYS$LOGIN:,$DISK1:[OLGA],$DISK2[SCRATCH.IVAN].",
+#else
+"  (unknown for this platform)",
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* UNIXOROSK */
+" ",
+"SET CD MESSAGE { ON, OFF }",
+"  Default is OFF.  When ON, this tells Kermit to look for a file with a",
+"  certain name in any directory that you CD to, and if it finds one, to",
+"  display it on your screen when you give the CD command.  The filename,",
+"  or list of names, is given in the SET CD MESSAGE FILE command.",
+" ",
+"SET CD MESSAGE FILE name",
+"  or:",
+"SET CD MESSAGE FILE {{name1}{name2}...{name8}}",
+"  Specify up to 8 filenames to look for when when CDing to a new directory",
+"  and CD MESSAGE is ON.  The first one found, if any, in the new directory",
+#ifndef DFCDMSG
+"  is displayed.",
+#else
+"  is displayed.  The default list is:",
+" ",
+#ifdef UNIXOROSK
+"   {{./.readme}{README.TXT}{READ.ME}}",
+#else
+"   {{README.TXT}{READ.ME}}",
+#endif /* UNIXOROSK */
+" ",
+#endif /* DFCDMSG */
+#ifndef NOSERVER
+"Synonym: SET SERVER CD-MESSAGE FILE.",
+#endif /* NOSERVER */
+" ",
+"Type SHOW CD to view current CD settings.  Also see HELP SET SERVER.",
+""
+};
+
+#ifndef NOIKSD
+static char * hsetiks[] = {
+#ifdef OS2
+"SET IKS ANONYMOUS ACCOUNT <username>",
+"  On Windows NT/2000 this is the account that will be used to allow",
+"  anonymous access to the system.  This account MUST have no password",
+"  and its privileges should be restricted to only allow those operations",
+"  which should be permitted to unknown users.  In practice this means",
+"  List Directories and Read-Execute privileges only.  If a directory",
+"  is configured for Write privileges then Read privileges should be",
+"  denied for that directory.  Otherwise, your system will become used",
+"  by software pirates.  If this command is not specified in the IKSD.KSC",
+"  file the username \"GUEST\" is used by default.  This command has no",
+"  effect on Windows 95/98.",
+" ",
+#endif /* OS2 */
+"SET IKS ANONYMOUS INITFILE filename",
+#ifdef OS2
+"  The initialization file to be executed for anonymous logins.  By default",
+"  it is K95.INI in the home directory associated with the ANNONYMOUS account."
+,
+"  Any filename that you specify here must be readable by the ANONYMOUS",
+"  account and if a SET IKS ANONYMOUS ROOT command was given, exist within",
+"  the restricted directory tree.  This option is independent of the SET IKS",
+"  INITFILE command which applies only to real users.",
+#else
+"  The initialization file to be executed for anonymous logins.  By default",
+"  it is .kermrc in the anonymous root directory.  This option is independent",
+"  of the SET IKS INITFILE command which applies only to real users.",
+#endif /* OS2 */
+" ",
+"SET IKS ANONYMOUS LOGIN { ON, OFF }",
+#ifdef OS2
+"  Whether anonymous logins are allowed.  By default they are NOT allowed,",
+"  so this option need be included only to allow them (or for clarity, to",
+"  emphasize that they are not allowed).  Anonymous login occurs when the",
+"  username \"anonymous\" is specified with any password (as with ftpd).",
+"  In order for anonymous logins to succeed on Windows NT/2000, the",
+"  ANONYMOUS account must be enabled.",
+" ",
+"  On Windows NT and 2000, anonymous users have the same access rights as",
+"  the ANONYMOUS account.  In Windows 95/98, anonymous users, just like any",
+"  other users, have full access rights to your entire PC, since Windows 95",
+"  and 98 include no security features.  For this reason, if you are allowing",
+"  anonymous logins, be sure to also SET an IKS ANONYMOUS ROOT directory to",
+"  restrict anonymous users' file access.",
+" ",
+"  Anonymous user permissions may be restricted via the specification of ",
+"  DISABLE commands in the ANONYMOUS initfile.  Anonymous users are not ",
+"  permitted to execute an ENABLE command.  Anonymous users are also prevented"
+,
+"  from SHOWing sensitive data about the operating system or the IKS",
+"  configuration.",
+#else
+"  Whether anonymous logins are allowed. By default they are allowed, so this",
+"  option need be included only to disallow them (or for clarity, to emphasize"
+,
+"  they are allowed). Anonymous login occurs when the username \"anonymous\"",
+"  or \"ftp\" is given, with any password (as with ftpd).",
+#endif /* OS2 */
+" ",
+"SET IKS ANONYMOUS ROOT <directory>",
+"  Specifies a directory tree to which anonymous users are restricted after",
+"  login.",
+" ",
+"SET IKS BANNERFILE <filename>",
+"  The name of a file containing a message to be printed after the user logs",
+"  in, in place of the normal message (copyright notice, \"Type HELP or ? for",
+"  help\", etc).",
+" ",
+"SET IKS CDFILE <filelist>",
+"  When cdmessage is on, this is the name of the \"read me\" file to be shown."
+,
+"  Normally you would specify a relative (not absolute) name, since the file",
+"  is opened using the literal name you specified, after changing to the new",
+"  directory.  Example:",
+" ",
+"    SET IKS CDFILE READ.ME",
+" ",
+"  You can also give a list of up to 8 filenames by (a) enclosing each",
+"  filename in braces, and (b) enclosing the entire list in braces.  Example:",
+" ",
+"    SET IKS CDFILE {{READ.ME}{aareadme.txt}{README}{read-this-first}}",
+" ",
+"  When a list is given, it is searched from left to right and the first",
+"  file found is displayed.",
+" ",
+"SET IKS CDMESSAGE {ON, OFF, 0, 1, 2}",
+"  For use in the Server-Side Server configuration; whenever the client",
+"  tells the server to change directory, the server sends the contents of a",
+"  \"read me\" file to the client's screen.  This feature is ON by default,",
+"  and operates in client/server mode only when ON or 1.  If set to 2 or",
+"  higher, it also operates when the CD command is given at the IKSD> prompt.",
+"  Synonym: SET IKS CDMSG.",
+" ",
+"SET IKS DATABASE { ON, OFF }",
+"  This command determines whether entries are inserted into the SET IKS",
+"  DBFILE (IKSD active sessions database).",
+" ",
+"SET IKS DBFILE <filename>",
+"  Specifies the file which should be used for storing runtime status",
+#ifdef OS2
+"  information about active connections.  The default is a file called",
+"  \"iksd.db\" in the WINDOWS directory.",
+#else
+#ifdef UNIX
+"  information about active connections.  The default is a file called",
+"  \"iksd.db\" in the /var/log directory.",
+#else
+"  information about active connections.",
+#endif /* UNIX */
+#endif /* OS2 */
+" ",
+#ifdef OS2
+"SET IKS DEFAULT-DOMAIN <domain-name>",
+"  A userid on Windows is of the form DOMAIN\\\\userid.  This command",
+"  determines which domain will be searched for the userid if a domain",
+"  is not specified by the user.  On Windows 95/98 when User-level",
+"  access is activated in the Network Control Panel, the default ",
+"  domain will be automatically set.  If the default domain is not",
+"  specified, accounts on the local machine will take precedence over",
+"  accounts in Domains to which the local machine belongs.",
+#endif /* OS2 */
+" ",
+"SET IKS HELPFILE <filename>",
+"  Specifies the name of a file to be displayed if the user types HELP",
+"  (not followed by a specific command or topic), in place of the built-in",
+"  top-level help text.  The file need not fit on one screen; more-prompting",
+"  is used if the file is more than one screen long if COMMAND MORE-PROMPTING",
+"  is ON, as it is by default.",
+" ",
+"SET IKS INITFILE <filename>",
+"  Execute <filename> rather than the normal initialization file for real",
+"  users; this option does not apply to anonymous users.",
+" ",
+"SET IKS NO-INITFILE { ON, OFF }",
+"  Do not execute an initialization file, even if a real user is logging in.",
+" ",
+"SET IKS SERVER-ONLY { ON, OFF }",
+"  If this option is included on the IKSD command line, the Client Side Server"
+,
+"  configuration is disabled, and the user will not get a Username: or",
+"  Password: prompt, and will not be able to access the IKSD command prompt.",
+"  A FINISH command sent to the IKSD will log it out and close the",
+"  connection, rather than returning it to its prompt.",
+" ",
+"SET IKS TIMEOUT <number>",
+"  This sets a limit (in seconds) on the amount of time the client has to log",
+"  in once the connection is made.  If successful login does not occur within",
+"  the given number of seconds, the connection is closed.  The default timeout"
+,
+"  is 300 seconds (5 minutes).  A value of 0 or less indicates there is to be",
+"  no limit.",
+" ",
+"SET IKS USERFILE <filename>",
+#ifdef UNIX
+"  This file contains a list of local usernames that are to be denied access",
+"  to Internet Kermit Service.  The default is /etc/ftpusers.  This can be the"
+,
+"  same file that is used by wuftpd, and the syntax is the same: one username",
+"  per line; lines starting with \"#\" are ignored.  Use this option to",
+"  specify the name of a different forbidden-user file, or use",
+"  \"set iks userfile /dev/null\" to disable this feature in case there is a",
+"   /etc/ftpusers file but you don't want to use it.",
+#else
+"  This file contains a list of local usernames that are to be denied access",
+"  to Internet Kermit Service.  The syntax is: one username per line; lines",
+"  starting with \"#\" are ignored.",
+#endif /* UNIX */
+" ",
+"SET IKS XFERLOG { ON, OFF }",
+#ifdef UNIX
+"  Whether a file-transfer log should be kept.  Off by default.  If \"on\",",
+"  but no SET IKSD XFERFILE command is given, /var/log/iksd.log is used.",
+#else
+"  Whether a file-transfer log should be kept.  Off by default.",
+#endif /* UNIX */
+" ",
+"SET IKS XFERFILE <filename>",
+"  Use this option to specify an iksd log file name.  If you include this",
+"  option, it implies SET IKS XFERFILE ON.",
+""
+};
+#endif /* NOIKSD */
+
+/*  D O H S E T  --  Give help for SET command  */
+
+int
+dohset(xx) int xx; {
+    int x;
+
+    if (xx == -3) return(hmsga(hmhset));
+    if (xx < 0) return(xx);
+
+#ifdef NEWFTP
+    if (xx == XYFTPX)
+      return(dosetftphlp());
+    if (xx == XYGPR)
+      return(hmsga(hmxygpr));
+#endif /* NEWFTP */
+
+    if ((x = cmcfm()) < 0) return(x);
+    switch (xx) {
+#ifndef NOIKSD
+      case XYIKS:
+        return(hmsga(hsetiks));
+#endif /* NOIKSD */
+
+case XYATTR:
+    return(hmsga(hsetat));
+
+case XYBACK:
+    return(hmsga(hsetbkg));
+
+case XYBELL:
+    return(hmsga(hmxybel));
+
+#ifdef OS2
+case XYPRTY:
+    return(hmsg("SET PRIORITY { REGULAR, FOREGROUND-SERVER, TIME-CRITICAL }\n\
+  Specifies at which priority level the communication and screen update\n\
+  threads should operate.  The default value is FOREGROUND-SERVER."));
+#endif /* OS2 */
+
+#ifdef DYNAMIC
+case XYBUF:
+    return(hmsga(hsetbuf));
+#endif /* DYNAMIC */
+
+#ifndef NOLOCAL
+case XYCARR:
+    return(hmsga(hsetcar));
+#endif /* NOLOCAL */
+
+#ifndef NOSPL
+case XYCASE:
+    return(hmsg("Syntax: SET CASE { ON, OFF }\n\
+  Tells whether alphabetic case is significant in string comparisons\n\
+  done by INPUT, IF, and other commands.  This setting is local to the\n\
+  current macro or command file, and inherited by subordinates."));
+
+#endif /* NOSPL */
+
+case XYCMD:
+    return(hmsga(hsetcmd));
+
+case XYIFD:
+    return(hmsg("Syntax: SET INCOMPLETE { DISCARD, KEEP }\n\
+  Whether to discard or keep incompletely received files, default is KEEP."));
+
+#ifndef NOSPL
+case XYINPU:
+    return(hmsga(hxyinp));
+#endif /* NOSPL */
+
+case XYCHKT:
+    return(hmsga(hmxychkt));
+
+#ifndef NOSPL
+case XYCOUN:
+    return(hmsg("Syntax:  SET COUNT number\n\
+ Example: SET COUNT 5\n\
+  Set up a loop counter, for use with IF COUNT.  Local to current macro\n\
+  or command file, inherited by subordinate macros and command files."));
+#endif /* NOSPL */
+
+case XYDEBU:
+    return(hmsga(hmxydeb));
+
+case XYDFLT:
+    return(hmsg("Syntax: SET DEFAULT directory\n\
+  Change directory.  Equivalent to CD command."));
+
+case XYDELA:
+    return(hmsg("Syntax: SET DELAY number\n\
+  Number of seconds to wait before sending first packet after SEND command."));
+
+#ifndef NODIAL
+case XYDIAL:
+    return(hmsga(hmxydial));
+#endif /* NODIAL */
+
+#ifdef UNIX
+case XYSUSP:
+    return(hmsg("Syntax: SET SUSPEND { OFF, ON }\n\
+  Disables SUSPEND command, suspend signals, and <esc-char>Z during CONNECT.")
+           );
+#endif
+
+#ifndef NOSCRIPT
+case XYSCRI:
+    return(hmsg("Syntax: SET SCRIPT ECHO { OFF, ON }\n\
+  Disables/Enables echoing of SCRIPT command operation."));
+#endif /* NOSCRIPT */
+
+case XYTAKE:
+    return(hmsga(hxytak));
+
+#ifndef NOLOCAL
+case XYTERM:
+    return(hmsga(hxyterm));
+
+case XYDUPL:
+    return(hmsg("Syntax: SET DUPLEX { FULL, HALF }\n\
+  During CONNECT: FULL means remote host echoes, HALF means Kermit\n\
+  does its own echoing."));
+
+case XYLCLE:
+    return(hmsg("Syntax: SET LOCAL-ECHO { OFF, ON }\n\
+  During CONNECT: OFF means remote host echoes, ON means Kermit\n\
+  does its own echoing.  Synonym for SET DUPLEX { FULL, HALF }."));
+
+case XYESC:
+    return(hmsga(hxyesc));              /* SET ESCAPE */
+#endif /* NOLOCAL */
+
+case XYPRTR:                            /* SET PRINTER */
+    return(hmsga(hxyprtr));
+
+#ifdef OS2
+#ifdef BPRINT
+case XYBDCP:                            /* SET BPRINTER */
+    return(hmsga(hxybprtr));
+#endif /* BPRINT */
+#endif /* OS2 */
+
+case XYEXIT:
+    return(hmsga(hxyexit));
+
+case XYFILE:
+    return(hmsga(hmxyf));
+
+case XYFLOW:
+    return(hmsga(hmxyflo));
+
+case XYHAND:
+   return(hmsga(hmxyhsh));
+
+#ifdef NETCONN
+
+case XYHOST:
+    return(hmsga(hxyhost));
+
+case XYNET:
+    return(hmsga(hxynet));
+
+#ifndef NOTCPOPTS
+#ifdef SOL_SOCKET
+case XYTCP:
+    return(hmsga(hxytcp));
+#endif /* SOL_SOCKET */
+#endif /* NOTCPOPTS */
+
+#ifdef ANYX25
+case XYX25:
+    return(hmsga(hxyx25));
+
+#ifndef IBMX25
+case XYPAD:
+    return(hmsg("Syntax: SET PAD name value\n\
+Set a PAD X.3 parameter with a desired value."));
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+#endif /* NETCONN */
+
+#ifndef NOSPL
+case XYOUTP:
+    return(hmsga(hxyout));
+#endif /* NOSPL */
+
+#ifndef NOSETKEY
+case XYKEY:                             /* SET KEY */
+    return(hmsga(hmhskey));
+#endif /* NOSETKEY */
+
+#ifndef NOCSETS
+case XYLANG:
+    return(hmsg("Syntax: SET LANGUAGE name\n\
+  Selects language-specific translation rules for text-mode file transfers.\n\
+  Used with SET FILE CHARACTER-SET and SET TRANSFER CHARACTER-SET when one\n\
+  of these is ASCII."));
+#endif /* NOCSETS */
+
+case XYLINE:
+    printf("\nSyntax: SET LINE (or SET PORT) [ switches ] [ devicename ]\n\
+  Selects a serial-port device to use for making connections.\n");
+#ifdef OS2
+#ifdef NT
+    printf("\n");
+    printf(
+"  You may access communication ports by the traditional \"DOS\" port name\n");
+    printf(
+"  (e.g. SET PORT COM1) or by the Microsoft Telephony modem name from the\n");
+    printf(
+"  Modems folder of the Control Panel (e.g. SET PORT TAPI). If one method\n");
+    printf("  doesn't work, try the other.\n\n");
+#endif /* NT */
+#else  /* OS2 */
+    printf("  Typical device name for this platform: %s.\n",ttgtpn());
+    printf("  The default device name is %s (i.e. none).\n",dftty);
+    if (!dfloc) {
+        printf(
+"  If you do not give a SET LINE command or if you give a SET LINE command\n");
+        printf(
+"  with no device name, or if you specify %s as the device name,\n",dftty);
+        printf(
+"  Kermit will be in \"remote mode\", suitable for use on the far end of a\n");
+        printf(
+"  connection, e.g. as the file-transfer partner of your desktop communication\
+\n");
+        printf(
+"  software.  If you SET LINE to a specific device other than %s,\n", dftty);
+        printf(
+"  Kermit is in \"local mode\", suitable for making a connection to another\n"
+              );
+        printf(
+"  computer.  SET LINE alone resets Kermit to remote mode.\n");
+    }
+#endif /* OS2 */
+        printf(
+"  To use a modem to dial out, first SET MODEM TYPE (e.g., to USR), then\n");
+    printf(
+#ifdef OS2
+"  SET PORT COMx (or SET PORT TAPI), SET SPEED, then give a DIAL command.\n");
+#else
+"  SET LINE xxx, then SET SPEED, then give a DIAL command.\n");
+#endif /* OS2 */
+    printf(
+#ifdef OS2
+"  For direct null-modem connections use SET MODEM TYPE NONE, SET PORT COMx,\n"
+#else
+"  For direct null-modem connections, use SET MODEM TYPE NONE, SET LINE xxx,\n"
+#endif /* OS2 */
+    );
+    printf(
+"  then SET FLOW, SET SPEED, and CONNECT.\n");
+    printf(
+"\nOptional switches:\n\
+  /CONNECT - Enter CONNECT mode automatically if SET LINE succeeds.\n");
+    printf(
+"  /SERVER  - Enter server mode automatically if SET LINE succeeds.\n");
+#ifdef VMS
+    printf(
+"  /SHARE   - Open the device in shared mode.\n");
+    printf(
+"  /NOSHARE - Open the device in exclusive mode.\n");
+#endif /* VMS */
+    printf("\n");
+    printf(
+"Also see HELP SET MODEM, HELP SET DIAL, HELP SET SPEED, HELP SET FLOW.\n");
+    return(0);
+
+#ifndef NOSPL
+case XYMACR:
+    return(hmsga(hxymacr));
+#endif /* NOSPL */
+
+#ifndef NODIAL
+case XYMODM:
+    return(hmsga(hxymodm));
+#endif /* NODIAL */
+
+case XYPARI:
+    return(hmsga(hxypari));
+
+case XYPROM:
+    return(hmsga(hmxyprm));
+
+case XYQUIE:
+    return(hmsg("Syntax: SET QUIET {ON, OFF}\n\
+  Normally OFF.  ON disables most information messages during interactive\n\
+  operation."));
+
+#ifdef CK_SPEED
+case XYQCTL:
+    return(hmsga(hmxyqctl));
+#endif /* CK_SPEED */
+
+case XYRETR:
+    return(hmsg("Syntax: SET RETRY number\n\
+  In Kermit protocol file transfers: How many times to retransmit a\n\
+  particular packet before giving up; 0 = no limit."));
+
+#ifndef NOLOCAL
+case XYSESS:
+#ifdef UNIX
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef datageneral
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef STRATUS
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef AMIGA
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef GEMDOS
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef OS2
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out NUL and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef VMS
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out CR, NUL, and XON/XOFF characters.  DEBUG is the same as BINARY but\n\
+  also includes Telnet negotiations on TCP/IP connections."));
+#else
+#ifdef OSK
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out LF, NUL and XON/XOFF characters."));
+#else
+#ifdef MAC
+    return(hmsg(
+"Syntax: SET SESSION-LOG { BINARY, DEBUG, TEXT, TIMESTAMPED-TEXT }\n\
+  If BINARY, record all CONNECT characters in session log.  If TEXT, strip\n\
+  out LF, NUL and XON/XOFF characters."));
+#endif /* MAC */
+#endif /* OSK */
+#endif /* OS2 */
+#endif /* VMS */
+#endif /* GEMDOS */
+#endif /* AMIGA */
+#endif /* STRATUS */
+#endif /* datageneral */
+#endif /* OS2ORUNIX */
+
+case XYSPEE:
+#ifdef OS2
+
+    return(hmsg("Syntax: SET SPEED number\n\
+  Speed for serial-port communication device specified in most recent\n\
+  SET PORT command, in bits per second.  Type SET SPEED ? for a list of\n\
+  possible speeds."));
+#else
+    return(hmsg("Syntax: SET SPEED number\n\
+  Speed for serial-port communication device specified in most recent\n\
+  SET LINE command, in bits per second.  Type SET SPEED ? for a list of\n\
+  possible speeds.  Has no effect on job's controlling terminal."));
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+case XYRECV:
+    return(hmsga(hxyrcv));
+case XYSEND:
+    return(hmsga(hxysnd));
+case XYREPT:
+    return(hmsga(hxyrpt));
+#endif /* NOXFER */
+
+#ifndef NOSERVER
+case XYSERV:
+    return(hmsga(hsetsrv));
+#endif /* NOSERVER */
+
+#ifdef TNCODE
+case XYTEL:
+    return(hmsga(hxytel));
+
+case XYTELOP:
+    return(hmsga(hxytopt));
+#endif /* TNCODE */
+
+#ifndef NOXMIT
+case XYXMIT:
+    return(hmsga(hsetxmit));
+#endif /* NOXMIT */
+
+#ifndef NOCSETS
+case XYUNCS:
+    return(hmsg("Syntax: SET UNKNOWN-CHAR-SET action\n\
+  DISCARD (default) means reject any arriving files encoded in unknown\n\
+  character sets.  KEEP means to accept them anyway."));
+#endif /* NOCSETS */
+
+#ifdef UNIX
+case XYWILD:
+    return(hmsga(hxywild));
+#endif /* UNIX */
+
+#ifndef NOXFER
+case XYWIND:
+    return(hmsga(hxywind));
+case XYXFER:
+    return(hmsga(hxyxfer));
+#endif /* NOXFER */
+
+#ifndef NOLOCAL
+#ifdef OS2MOUSE
+case XYMOUSE:
+    return(hmsga(hxymouse));
+#endif /* OS2MOUSE */
+#endif /* NOLOCAL */
+
+case XYALRM:
+    return(hmsg("Syntax: SET ALARM [ { seconds, hh:mm:ss } ]\n\
+  Number of seconds from now, or time of day, after which IF ALARM\n\
+  will succeed.  0, or no time at all, means no alarm."));
+
+case XYPROTO:
+    return(hmsga(hxyxyz));
+
+#ifdef CK_SPEED
+case XYPREFIX:
+    return(hmsg("Syntax: SET PREFIXING { ALL, CAUTIOUS, MINIMAL }\n\
+  \
+Selects the degree of control-character prefixing.  Also see HELP SET CONTROL."
+));
+#endif /* CK_SPEED */
+
+#ifdef OS2
+case XYLOGIN:
+    return(hmsg("Syntax: SET LOGIN { USERID, PASSWORD, PROMPT } <text>\n\
+  Provides access information for use by login scripts."));
+#endif /* OS2 */
+
+#ifndef NOSPL
+case XYTMPDIR:
+    return(hmsg("Syntax: SET TEMP-DIRECTORY [ <directory-name> ]\n\
+  Overrides automatic assignment of \\v(tmpdir) variable."));
+#endif /* NOSPL */
+
+#ifdef OS2
+case XYTITLE:
+    return(hmsg("Syntax: SET TITLE <text>\n\
+  Sets window title to text instead of using current host/port name."));
+#endif /* OS2 */
+
+#ifndef NOPUSH
+#ifndef NOFRILLS
+case XYEDIT:
+    return(hmsg("Syntax: SET EDITOR pathname [ options ]\n\
+  Specifies the name of your preferred editor, plus any command-line\n\
+  options.  SHOW EDITOR displays it."));
+#endif /* NOFRILLS */
+#endif /* NOPUSH */
+
+#ifdef BROWSER
+case XYBROWSE:
+#ifdef NT
+    return(hmsg("Syntax: SET BROWSER [ pathname [ options ] ]\n\
+  Specifies the name of your preferred browser plus any command-line\n\
+  options.  SHOW BROWSER displays it.  Omit pathname and options to use\n\
+  ShellExecute."));
+#else
+    return(hmsg("Syntax: SET BROWSER [ pathname [ options ] ]\n\
+  Specifies the name of your preferred browser plus any command-line\n\
+  options.  SHOW BROWSER displays it."));
+#endif /* NT */
+#endif /* BROWSER */
+
+#ifdef CK_TAPI
+case XYTAPI:
+    return(hmsga(hxytapi));
+#endif /* CK_TAPI */
+
+#ifdef NT
+case XYWIN95:
+    return(hmsga(hxywin95));
+#endif /* NT */
+
+#ifndef NOSPL
+case XYFUNC:
+    return(hmsga(hxyfunc));
+#endif /* NOSPL */
+
+#ifdef CK_AUTHENTICATION
+case XYAUTH:
+    return(hmsga(hmxyauth));
+#else /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+case XYAUTH:
+    return(hmsga(hmxyauth));
+#endif /* CK_SSL */
+#endif /* CK_AUTHENTICATION */
+
+#ifdef BROWSER
+case XYFTP:
+    return(hmsg("Syntax: SET FTP [ pathname [ options ] ]\n\
+  Specifies the name of your ftp client, plus any command-line options.\n\
+  SHOW FTP displays it."));
+#endif /* BROWSER */
+
+case XYSLEEP:
+    return(hmsg("Syntax: SET SLEEP CANCELLATION { ON, OFF }\n\
+  Tells whether SLEEP (PAUSE) or WAIT commands can be interrupted from the\n\
+  keyboard; ON by default."));
+
+case XYCD:
+    return(hmsga(hmxycd));
+
+case XYSERIAL:
+    return(hmsg("Syntax: SET SERIAL dps\n\
+  d is data length in bits, 7 or 8; p is first letter of parity; s is stop\n\
+  bits, 1 or 2.  Examples: \"set serial 7e1\", \"set serial 8n1\"."));
+
+#ifdef HWPARITY
+case XYSTOP:
+    return(hmsg("Syntax: SET STOP-BITS { 1, 2 }\n\
+  Number of stop bits to use on SET LINE connections, normally 1."));
+#endif /* HWPARITY */
+
+#ifndef NOLOCAL
+case XYDISC:
+    return(hmsg("Syntax: SET DISCONNECT { ON, OFF }\n\
+  Whether to close and release a SET LINE device automatically upon\n\
+  disconnection; OFF = keep device open (default); ON = close and release."));
+#endif /* NOLOCAL */
+
+#ifdef STREAMING
+case XYSTREAM:
+    return(hmsg("Syntax: SET STREAMING { ON, OFF, AUTO }\n\
+  Tells Kermit whether streaming protocol can be used during Kermit file\n\
+  transfers.  Default is AUTO, meaning use it if connection is reliable."));
+#endif /* STREAMING */
+
+case XYRELY:
+    return(hmsg("Syntax: SET RELIABLE { ON, OFF, AUTO }\n\
+  Tells Kermit whether its connection is reliable.  Default is AUTO,\n\
+  meaning Kermit should figure it out for itself."));
+
+case XYCLEAR:
+    return(hmsg("Syntax: SET CLEAR-CHANNEL { ON, OFF, AUTO }\n\
+  Tells Kermit whether its connection is transparent to all 8-bit bytes.\n\
+  Default is AUTO, meaning Kermit figures it out from the connection type.\n\
+  When both sender and receiver agree channel is clear, SET PREFIXING NONE\n\
+  is used automatically."));
+
+#ifdef TLOG
+case XYTLOG:
+    return(hmsg("Syntax: SET TRANSACTION-LOG { BRIEF, FTP, VERBOSE }\n\
+  Selects the transaction-log format; BRIEF and FTP have one line per file;\n\
+  FTP is compatible with FTP log.  VERBOSE (the default) has more info."));
+#endif /* TLOG */
+
+case XYOPTS:
+    return(hmsg("Syntax: SET OPTIONS command [ switches... ]\n\
+  For use with commands that have switches; sets the default switches for\n\
+  the given command.  Type SET OPTIONS ? for a list of amenable commands."));
+
+#ifndef NOSPL
+case XYTIMER:
+    return(hmsga(hmxytimer));
+#endif /* NOSPL */
+
+#ifdef CKROOT
+  case XYROOT:
+    return(hmsga(hmxxchroot));
+#endif /* XYROOT */
+
+#ifdef ANYSSH
+  case XYSSH:
+    return(hmsga(hmxyssh));
+#endif /* ANYCMD */
+
+#ifdef LOCUS
+  case XYLOCUS:
+    return(hmsga(hmxylocus));
+#endif /* LOCUS */
+
+#ifdef OS2
+#ifdef KUI
+  case XYGUI:
+    return(hmsga(hmxygui));
+#endif /* KUI */
+#endif /* OS2 */
+
+  case XYMATCH:
+    return(hmsga(hmxymatch));
+
+default:
+    printf("Not available - \"%s\"\n",cmdbuf);
+    return(0);
+    }
+}
+
+#ifndef NOSPL
+/*  D O H F U N C  --  Give help for a function  */
+
+int
+dohfunc(xx) int xx; {
+    /* int x; */
+    if (xx == -3) {
+        printf("\n Type SHOW FUNCTIONS to see a list of available functions.\n"
+               );
+        printf(
+        " Type HELP FUNCTION <name> for help on a particular function.\n");
+        printf(
+        " For function settings use HELP SET FUNCTION and SHOW SCRIPTS.\n\n");
+        return(0);
+    }
+    if (xx == FN_WORD)                  /* Long help message */
+        return(hmsga(hmfword));
+
+    printf("\n");
+    switch (xx) {
+      case FN_IND:                      /* Index (of string 1 in string 2) */
+      case FN_RIX:                      /* Rindex (index from right) */
+        printf("\\f%sindex(s1,s2,n1)\n\
+  s1 = string to look for.\n\
+  s2 = string to look in.\n\
+  n1 = optional 1-based starting position, default = 1.\n",
+               xx == FN_RIX ? "r" : ""
+               );
+        printf("Returns integer:\n\
+  1-based position of %smost occurrence of s1 in s2, ignoring the %smost\n\
+  (n1-1) characters in s2; returns 0 if s1 not found in s2.\n",
+               xx == FN_IND ? "left" : "right",
+               xx == FN_IND ? "left" : "right"
+        );
+        break;
+      case FN_SEARCH:                   /* Search for pattern */
+      case FN_RSEARCH:                  /* Search for pattern from right */
+        printf("\\f%ssearch(s1,s2,n1)\n\
+  s1 = pattern to look for.\n\
+  s2 = string to look in.\n\
+  n1 = optional 1-based offset, default = 1.\n",
+               xx == FN_RSEARCH ? "r" : ""
+               );
+        printf("Returns integer:\n\
+  1-based position of %smost match for s1 in s2, ignoring the %smost\n\
+  (n1-1) characters in s2; returns 0 if no match.\n",
+               xx == FN_SEARCH ? "left" : "right",
+               xx == FN_SEARCH ? "left" : "right"
+        );
+        printf("  See HELP WILDCARDS for info about patterns.\n");
+        break;
+      case FN_LEN:                      /* Length (of string) */
+        printf("\\flength(s1)\n\
+  s1 = string.\n");
+        printf("Returns integer:\n\
+  Length of string s1.\n");
+        break;
+      case FN_LIT:                      /* Literal (don't expand the string) */
+        printf("\\fliteral(s1)\n\
+  s1 = string.\n");
+        printf("Returns string:\n\
+  s1 literally without evaluation.\n");
+        break;
+      case FN_LOW:                      /* Lower (convert to lowercase) */
+        printf("\\flower(s1)\n\
+  s1 = string.\n");
+        printf("Returns string:\n\
+  s1 with uppercase letters converted to lowercase.\n");
+        break;
+      case FN_MAX:                      /* Max (maximum) */
+        printf("\\fmaximum(n1,n2)\n\
+  n1 = integer.\n\
+  n2 = integer.\n");
+        printf("Returns integer:\n\
+  The greater of n1 and n2.\n");
+        break;
+      case FN_MIN:                      /* Min (minimum) */
+        printf("\\fminimum(n1,n2)\n\
+  n1 = integer.\n\
+  n2 = integer.\n");
+        printf("Returns integer:\n\
+  The lesser of n1 and n2.\n");
+        break;
+      case FN_MOD:                      /* Mod (modulus) */
+        printf("\\fmodulus(n1,n2)\n\
+  n1 = integer.\n\
+  n2 = integer.\n");
+        printf("Returns integer:\n\
+  The remainder after dividing n1 by n2.\n");
+        break;
+      case FN_EVA:                      /* Eval (evaluate arith expression) */
+        printf("\\fevaluate(e)\n\
+  e = arithmetic expression.\n");
+        printf("Returns integer:\n\
+  The result of evaluating the expression.\n");
+        break;
+      case FN_SUB:                      /* Substr (substring) */
+        printf("\\fsubstring(s1,n1,n2)\n\
+  s1 = string.\n\
+  n1 = integer, 1-based starting position, default = 1.\n\
+  n2 = integer, length, default = length(s1) - n1 + 1.\n");
+        printf("Returns string:\n\
+  Substring of s1 starting at n1, length n2.\n");
+        break;
+      case FN_UPP:                      /* Upper (convert to uppercase) */
+        printf("\\fupper(s1)\n\
+  s1 = string.\n");
+        printf("Returns string:\n\
+  s1 with lowercase letters converted to uppercase.\n");
+        break;
+      case FN_REV:                      /* Reverse (a string) */
+        printf("\\freverse(s1)\n\
+  s1 = string.\n");
+        printf("Returns string:\n\
+  s1 with its characters in reverse order.\n");
+        break;
+      case FN_REP:                      /* Repeat (a string) */
+        printf("\\frepeat(s1,n1)\n\
+  s1 = string.\n\
+  n1 = integer.\n");
+        printf("Returns string:\n\
+  s1 repeated n1 times.\n");
+        break;
+      case FN_EXE:                      /* Execute (a macro) */
+        printf("\\fexecute(m1,a1,a2,a3,...)\n\
+  m1 = macro name.\n\
+  a1 = argument 1.\n\
+  a2 = argument 2, etc\n");
+        printf("Returns string:\n\
+  The return value of the macro (HELP RETURN for further info).\n");
+        break;
+      case FN_LPA:                      /* LPAD (left pad) */
+      case FN_RPA:                      /* RPAD (right pad) */
+        printf("\\f%cpad(s1,n1,c1)\n\
+  s1 = string.\n\
+  n1 = integer.\n\
+  c1 = character, default = space.\n",
+                xx == FN_LPA ? 'l' : 'r');
+        printf("Returns string:\n\
+  s1 %s-padded with character c1 to length n1.\n",
+               xx == FN_LPA ? "left" : "right");
+        break;
+      case FN_DEF:                      /* Definition of a macro, unexpanded */
+        printf("\\fdefinition(m1)\n\
+  m1 = macro name.\n");
+        printf("Returns string:\n\
+  Literal definition of macro m1.\n");
+        break;
+      case FN_CON:                      /* Contents of a variable, ditto */
+        printf("\\fcontents(v1)\n\
+  v1 = variable name such as \\%%a.\n");
+        printf("Returns string:\n\
+  Literal definition of variable v1, evaluated one level only.\n");
+        break;
+      case FN_FIL:                      /* Next file */
+        printf("\\fnextfile()\n");
+        printf("Returns string:\n\
+  Name of next file from list created by most recent \\f[r]files() or\n\
+  \\f[r]dir()invocation, or an empty string if there are no more files in\n\
+  the list.\n");
+        break;
+      case FN_FC:                       /* File count */
+        printf("\\ffiles(f1[,&a]) - File list.\n\
+  f1 = file specification, possibly containing wildcards.\n\
+  &a = optional name of array to assign file list to.\n");
+        printf("Returns integer:\n\
+  The number of regular files that match f1.  Use with \\fnextfile().\n");
+        break;
+      case FN_CHR:                      /* Character (like BASIC CHR$()) */
+        printf("\\fcharacter(n1)\n\
+  n1 = integer.\n");
+        printf("Returns character:\n\
+  The character whose numeric code is n1.\n");
+        break;
+      case FN_RIG:                      /* Right (like BASIC RIGHT$()) */
+        printf("\\fright(s1,n1)\n\
+  s1 = string.\n\
+  n1 = integer, default = length(s1).\n");
+        printf("Returns string:\n\
+  The rightmost n1 characters of string s1.\n");
+        break;
+      case FN_LEF:                      /* Left (like BASIC LEFT$()) */
+        printf("\\fleft(s1,n1)\n\
+  s1 = string.\n\
+  n1 = integer, default = length(s1).\n");
+        printf("Returns string:\n\
+  The leftmost n1 characters of string s1.\n");
+        break;
+      case FN_COD:                      /* Code value of character */
+        printf("\\fcode(s1)\n\
+  c1 = character.\n");
+        printf("Returns integer:\n\
+  The numeric code of the first character in string s1, or 0 if s1 empty.\n");
+        break;
+      case FN_RPL:                      /* Replace */
+        printf("\\freplace(s1,s2,s3[,n1])\n\
+  s1 = original string.\n\
+  s2 = match string.\n\
+  s3 = replacement string.\n\
+  n1 = occurrence.\n");
+        printf("Returns string:\n\
+  s1 with occurrence number n1 of s2 replaced by s3.\n\
+  If n1 = 0 or omitted, all occurrences are replaced.\n\
+  If n1 < 0, occurrences are counted from the right.\n");
+        break;
+
+      case FN_FD:                       /* File date */
+        printf("\\fdate(f1)\n\
+  f1 = filename.\n");
+#ifdef VMS
+        printf("Returns string:\n\
+  Creation date of file f1, format: yyyymmdd hh:mm:ss.\n");
+#else
+        printf("Returns string:\n\
+  Modification date of file f1, format: yyyymmdd hh:mm:ss.\n");
+#endif /* VMS */
+        break;
+      case FN_FS:                       /* File size */
+        printf("\\fsize(f1)\n\
+  f1 = filename.\n");
+        printf("Returns integer:\n\
+  Size of file f1.\n");
+        break;
+      case FN_VER:                      /* Verify */
+        printf("\\fverify(s1,s2,n1)\n\
+  s1 = string of characters to look for.\n\
+  s2 = string to look in.\n\
+  n1 = starting position in s2.\n");
+        printf("Returns integer:\n\
+  1-based position of first character in s2 that is not also in s1,\n\
+  or -1 if s1 is empty, or 0 if all characters in s2 are also in s1.\n");
+        break;
+      case FN_IPA:                      /* Find and return IP address */
+        printf("\\fipaddress(s1,n1)\n\
+  s1 = string.\n\
+  n1 = 1-based integer starting position, default = 1.\n");
+        printf("Returns string:\n\
+  First IP address in s1, scanning from left starting at position n1.\n");
+        break;
+      case FN_HEX:                      /* Hexify */
+        printf("\\fhexify(s1)\n\
+  s1 = string.\n");
+        printf("Returns string:\n\
+  The hexadecimal representation of s1.  Also see \\fn2hex().\n");
+        break;
+      case FN_UNH:                      /* Unhexify */
+        printf("\\funhexify(h1)\n\
+  h1 = Hexadecimal string.\n");
+        printf("Returns string:\n\
+  The result of unhexifying s1, or nothing if s1 is not a hex string.\n");
+        break;
+      case FN_UNTAB:                   /* Untabify */
+        printf("\\funtabify(s1)\n\
+  s1 = string.\n");
+        printf("Returns string:\n\
+  The result of converting tabs in s1 to spaces assuming tab stops every\n\
+  8 spaces.\n");
+        break;
+      case FN_BRK:                      /* Break */
+      case FN_SPN:                      /* Span */
+        printf("\\f%s(s1,s2,n1)\n\
+  s1 = string to look in.\n\
+  s2 = string of characters to look for.\n\
+  n1 = 1-based integer starting position, default = 1.\n",
+              xx == FN_BRK ? "break" : "span"
+              );
+        printf("Returns string:\n\
+  s1 up to the first occurrence of any character%salso in s2,\n\
+  scanning from the left starting at position n1.\n",
+               xx == FN_SPN ? " not " : " ");
+        break;
+      case FN_TRM:                      /* Trim */
+      case FN_LTR:                      /* Left-Trim */
+        printf("\\f%s(s1,s2)\n\
+  s1 = string to look in.\n\
+  s2 = string of characters to look for, default = blanks and tabs.\n",
+               xx == FN_TRM ? "trim" : "ltrim");
+        printf("Returns string:\n\
+  s1 with all characters that are also in s2 trimmed from the %s.\n.",
+               xx == FN_TRM ? "right" : "left");
+        break;
+      case FN_CAP:                      /* Capitalize */
+        printf("\\fcapitalize(s1)\n\
+  s1 = string.\n");
+        printf("Returns string:\n\
+  s1 with its first letter converted to uppercase and the remaining\n\
+  letters to lowercase.\n");
+        printf("Synonym: \\fcaps(s1)\n");
+        break;
+      case FN_TOD:                      /* Time-of-day-to-secs-since-midnite */
+        printf("\\ftod2secs(s1)\n\
+  s1 = time-of-day string, hh:mm:ss, 24-hour format.\n");
+        printf("Returns number:\n\
+  Seconds since midnight.\n");
+        break;
+      case FN_FFN:                      /* Full file name */
+        printf("\\fpathname(f1)\n\
+  f1 = filename, possibly wild.\n");
+        printf("Returns string:\n\
+  Full pathname of f1.\n");
+        break;
+      case FN_CHK:                      /* Checksum of text */
+        printf("\\fchecksum(s1)\n\
+  s1 = string.\n");
+        printf("Returns integer:\n\
+  16-bit checksum of string s1.\n");
+        break;
+      case FN_CRC:                      /* CRC-16 of text */
+        printf("\\fcrc16(s1)\n\
+  s1 = string.\n");
+        printf("Returns integer:\n\
+  16-bit cyclic redundancy check of string s1.\n");
+        break;
+      case FN_BSN:                      /* Basename of file */
+        printf("\\fbasename(f1)\n\
+  f1 = filename, possibly wild.\n");
+        printf("Returns string:\n\
+  Filename f1 stripped of all device and directory information.\n");
+        break;
+      case FN_CMD:                      /* Output of a command (cooked) */
+        printf("\\fcommand(s1)\n\
+  s1 = string\n");
+        printf("Returns string:\n\
+  Output of system command s1, if any, with final line terminator stripped.\n"
+               );
+        break;
+      case FN_RAW:                      /* Output of a command (raw) */
+        printf("\\frawcommand(s1)\n\
+  s1 = string\n");
+        printf("Returns string:\n\
+  Output of system command s1, if any.\n");
+        break;
+      case FN_STX:                      /* Strip from right */
+        printf("\\fstripx(s1,c1)\n\
+  s1 = string to look in.\n\
+  c1 = character to look for, default = \".\".\n");
+        printf("Returns string:\n\
+  s1 up to the rightmost occurrence of character c1.\n"
+        );
+        break;
+
+      case FN_STL:                      /* Strip from left */
+        printf("\\flop(s1,c1)\n\
+  s1 = string to look in.\n\
+  c1 = character to look for, default = \".\".\n");
+        printf("Returns string:\n\
+  The part of s1 after the leftmost occurrence of character c1.\n"
+        );
+        break;
+
+      case FN_STN:                      /* Strip n chars */
+        printf("\\fstripn(s1,n1)\n\
+  s1 = string to look in.\n\
+  n1 = integer, default = 0.\n");
+        printf("Returns string:\n\
+  s1 with n1 characters removed from the right.\n"
+        );
+        break;
+
+      case FN_STB:                      /* Strip enclosing brackets */
+        printf("\\fstripb(s1[,c1[,c2]])\n\
+  s1 = original string.\n\
+  c1 = optional first character\n");
+        printf("\
+  c2 = optional final character.\n");
+        printf("Returns string:\n\
+  s1 with the indicated enclosing characters removed.  If c1 and c2 not\n\
+     specified, any matching brackets, braces, parentheses, or quotes are\n");
+        printf("\
+     assumed.  If c1 is given but not c2, the appropriate c2 is assumed.\n\
+     if both c1 and c2 are given, they are used as-is.\n"
+               );
+        printf(
+"Alternative format:\n\
+  Include a grouping mask number in place of c1 and omit c2 to specify more\n\
+  than one possibility at once; see \\fword() for details.\n"
+               );
+        break;
+
+#ifdef OS2
+      case FN_SCRN_CX:                  /* Screen Cursor X Pos */
+        printf("\\fscrncurx()\n");
+        printf("Returns integer:\n\
+  The 0-based X coordinate (column) of the Terminal screen cursor.\n");
+        break;
+      case FN_SCRN_CY:                  /* Screen Cursor Y Pos */
+        printf("\\fscrncury()\n");
+        printf("Returns integer:\n\
+  The 0-based Y coordinate (row) of the Terminal screen cursor.\n");
+        break;
+      case FN_SCRN_STR:                 /* Screen String */
+        printf("\\fscrnstr(ny,nx,n1)\n\
+  ny = integer.\n\
+  nx = integer.\n\
+  n1 = integer.\n");
+        printf("Returns string:\n\
+  The string at Terminal-screen coordinates (nx,ny), length n1,\n\
+  blanks included.  Coordinates start at 0.  Default values are\n\
+  0 for ny and nx, and line width for n1.\n");
+        break;
+#endif /* OS2 */
+
+      case FN_2HEX:                     /* Num to hex */
+        printf("\\fn2hex(n1) - Number to hex\n  n1 = integer.\n");
+        printf("Returns string:\n  The hexadecimal representation of n1.\n");
+        break;
+
+      case FN_2OCT:                     /* Num to hex */
+        printf("\\fn2octal(n1) - Number to octal\n  n1 = integer.\n");
+        printf("Returns string:\n  The octal representation of n1.\n");
+        break;
+
+#ifdef RECURSIVE
+      case FN_DIR:                      /* Recursive directory count */
+        printf("\\fdirectories(f1) - Directory list.\n\
+  f1 = directory specification, possibly containing wildcards.\n\
+  &a = optional name of array to assign directory list to.\n");
+        printf("Returns integer:\n\
+  The number of directories that match f1; use with \\fnextfile().\n");
+        break;
+
+      case FN_RFIL:                     /* Recursive file count */
+        printf("\\frfiles(f1[,&a]) - Recursive file list.\n\
+  f1 = file specification, possibly containing wildcards.\n\
+  &a = optional name of array to assign file list to.\n");
+        printf("Returns integer:\n\
+  The number of files whose names match f1 in the current or given\n\
+  directory tree; use with \\fnextfile().\n");
+        break;
+
+      case FN_RDIR:                     /* Recursive directory count */
+        printf("\\frdirectories(f1) - Recursive directory list.\n\
+  f1 = directory specification, possibly containing wildcards.\n\
+  &a = optional name of array to assign directory list to.\n");
+        printf("Returns integer:\n\
+  The number of directories that match f1 in the current or given directory\n\
+  tree.  Use with \\fnextfile().\n");
+        break;
+#endif /* RECURSIVE */
+
+      case FN_DNAM:                     /* Directory part of a filename */
+        printf("\\fdirname(f) - Directory part of a filename.\n\
+  f = a file specification.\n");
+        printf("Returns directory name:\n\
+  The full name of the directory that the file is in, or if the file is a\n\
+  directory, its full name.\n");
+        break;
+
+#ifndef NORANDOM
+      case FN_RAND:                     /* Random number */
+        printf("\\frandom(n) - Random number.\n\
+  n = a positive integer.\n");
+        printf("Returns integer:\n\
+  A random number between 0 and n-1.\n");
+        break;
+#endif /* NORANDOM */
+
+      case FN_SPLIT:                    /* Split */
+        printf("\\fsplit(s1,&a,s2,s3,n2,n3) - \
+Assign string words to an array.\n\
+  s1 = source string\n  &a = array designator\n  s2 = optional break set.\n");
+        printf("  s3 = optional include set.\n");
+        printf("  n2 = optional grouping mask.\n");
+        printf("  n3 = optional separator flag.\n");
+        printf("  s2, s3, n2, n3 are as in \\fword().\n");
+        printf(
+"  All arguments are optional; if \\&a[] already exists, it is recycled;\n\
+  if array not specified, the count is returned but no array is created.\n");
+        printf("Returns integer:\n\
+  Number of words in source string.\n");
+        break;
+
+      case FN_DTIM:                     /* CVTDATE */
+        printf("\\fcvtdate([date-time][,n1]) - Date/time conversion.\n");
+        printf("  Converts date and/or time to standard format.\n");
+        printf("  If no date/time given, returns current date/time.\n");
+        printf("  [date-time], if given, is free-format date and/or time.\n");
+        printf("  HELP DATE for info about date-time formats.\n");
+        printf("Returns string:\n\
+  Standard-format date and time: yyyymmdd hh:mm:ss (numeric)\n");
+        printf("  If n1 is given:\n\
+  n1 = 1: yyyy-mmm-dd hh:mm:ss (mmm = English 3-letter month abbreviation)\n\
+  n1 = 2: dd-mmm-yyyy hh:mm:ss (ditto)\n\
+  n1 = 3: yyyymmddhhmmss (all numeric)\n");
+        break;
+
+      case FN_JDATE:                    /* DOY */
+        printf("\\fdoy([date-time]) - Day of Year.\n");
+        printf("  Converts date and/or time to day-of-year (DOY) format.\n");
+        printf("  If no date/time given, returns current date.\n");
+        printf("  [date-time], if given, is free-format date and/or time.\n");
+        printf("  HELP DATE for info about date-time formats.\n");
+        printf("Returns numeric string:\n\
+  DOY: yyyyddd, where ddd is 1-based day number in year.\n");
+        break;
+
+      case FN_PNCVT:
+        printf("\\fdialconvert(phone-number) - Convert phone number.\n");
+        printf("  Converts the given phone number for dialing according\n");
+        printf(
+"  to the prevailing dialing rules -- country code, area code, etc.\n");
+        printf("Returns string:\n\
+  The dial string that would be used if the same phone number had been\n\
+  given to the DIAL command.\n"
+              );
+        break;
+
+      case FN_DATEJ:                    /* DOY2DATE */
+        printf("\\fdoy2date([doy[ time]]) - Day of Year to Date.\n");
+        printf("  Converts yyyymmm to yyyymmdd\n");
+        printf("  If time included, it is converted to 24-hour format.");
+        printf(
+            "Returns standard date or date-time string yyyymmdd hh:mm:ss\n");
+        break;
+
+      case FN_MJD:
+        printf("\\fmjd([[date][ time]]) - Modified Julian Date (MJD).\n");
+        printf(
+"  Converts date and/or time to MJD, the number of days since 17 Nov 1858.\n");
+        printf("  HELP DATE for info about date-time formats.\n");
+        printf("Returns: integer.\n");
+        break;
+
+      case FN_MJD2:
+        printf("\\fmjd2date(mjd) - Modified Julian Date (MJD) to Date.\n");
+        printf("  Converts MJD to standard-format date.\n");
+        printf("Returns: yyyymmdd.\n");
+        break;
+
+      case FN_DAY:
+        printf("\\fday([[date][ time]]) - Day of Week.\n");
+        printf("Returns day of week of given date as Mon, Tue, etc.\n");
+        printf("HELP DATE for info about date-time formats.\n");
+        break;
+
+      case FN_NDAY:
+        printf("\\fnday([[date][ time]]) - Numeric Day of Week.\n");
+        printf(
+    "Returns numeric day of week of given date, 0=Sun, 1=Mon, ..., 6=Sat.\n");
+        printf("HELP DATE for info about date-time formats.\n");
+        break;
+
+      case FN_TIME:
+        printf("\\ftime([[date][ time]]) - Time.\n");
+        printf(
+"Returns time portion of given date and/or time in hh:mm:ss format.\n");
+        printf("If no argument given, returns current time.\n");
+        printf("HELP DATE for info about date-time formats.\n");
+        break;
+
+      case FN_NTIM:
+        printf("\\fntime([[date][ time]]) - Numeric Time.\n");
+        printf(
+"Returns time portion of given date and/or time as seconds since midnight.\n");
+        printf("If no argument given, returns current time.\n");
+        printf("HELP DATE for info about date-time formats.\n");
+        break;
+
+      case FN_N2TIM:
+        printf("\\fn2time(seconds) - Numeric Time to Time.\n");
+        printf(
+"Returns the given number of seconds in hh:mm:ss format.\n");
+        break;
+
+      case FN_PERM:
+        printf("\\fpermissions(file) - Permissions of File.\n");
+        printf(
+#ifdef UNIX
+"Returns permissions of given file as they would be shown by \"ls -l\".\n"
+#else
+#ifdef VMS
+"Returns permissions of given file as they would be shown by \"dir /prot\".\n"
+#else
+"Returns the permissions of the given file.\n"
+#endif /* VMS */
+#endif /* UNIX */
+               );
+        break;
+
+      case FN_ALOOK:
+        printf("\\farraylook(pattern,&a) - Lookup pattern in array.\n\
+  pattern = String or pattern\n");
+        printf("  &a = array designator, can include range specifier.\n");
+        printf(
+"Returns number:\n\
+  The index of the first matching array element or -1 if none.\n");
+        printf("More info:\n\
+  HELP PATTERN for pattern syntax.\n  HELP ARRAY for arrays.\n");
+        break;
+
+      case FN_TLOOK:
+        printf(
+"\\ftablelook(keyword,&a,[c]) - Lookup keyword in keyword table.\n\
+  pattern = String\n");
+        printf("  keyword = keyword to look up (can be abbreviated).\n");
+        printf("  &a      = array designator, can include range specifier.\n");
+        printf("            This array must be in alphabetical order.\n");
+        printf("  c       = Optional field delimiter, colon(:) by default.\n");
+        printf(
+"Returns number:\n\
+  1 or greater, index of array element that uniquely matches given keyword;\n"
+               );
+        printf(
+"or -2 if keyword was ambiguous, or -1 if keyword empty or not found.\n"
+               );
+        printf("Also see:\n\
+  HELP FUNC ARRAYLOOK for a similar function.\n  HELP ARRAY for arrays.\n");
+        break;
+
+      case FN_ABS:                      /* Absolute */
+        printf("\\fabsolute(n1)\n\
+  n1 = integer.\n");
+        printf("Returns integer:\n\
+  The absolute (unsigned) value of n1.\n");
+        break;
+
+#ifdef FNFLOAT
+      case FN_FPABS:
+        printf("\\ffpabsolute(f1,d)\n\
+  f1 = floating-point number or integer.\n\
+   d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The absolute (unsigned) value of f1 to d decimal places.\n");
+        break;
+
+      case FN_FPADD:
+        printf("\\ffpadd(f1,f2,d)\n\
+  f1,f2 = floating-point numbers or integers.\n\
+      d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The sum of f1 and f2 to d decimal places.\n");
+        break;
+
+      case FN_FPSUB:
+        printf("\\ffpsubtract(f1,f2,d)\n\
+  f1,f2 = floating-point numbers or integers.\n\
+      d = integer.\n");
+        printf("Returns floating-point number:\n\
+  f1 minus f2 to d decimal places.\n");
+        break;
+
+      case FN_FPMUL:
+        printf("\\ffpmultiply(f1,f2,d)\n\
+  f1,f2 = floating-point numbers or integers.\n\
+      d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The product of f1 and f2 to d decimal places.\n");
+        break;
+
+      case FN_FPDIV:
+        printf("\\ffpdivide(f1,f2,d)\n\
+  f1,f2 = floating-point numbers or integers.\n\
+      d = integer.\n");
+        printf("Returns floating-point number:\n\
+  f1 divided by f2 to d decimal places.\n");
+        break;
+
+      case FN_FPMAX:
+        printf("\\ffpmaximum(f1,f2,d)\n\
+  f1,f2 = floating-point numbers or integers.\n\
+      d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The maximum of f1 and f2 to d decimal places.\n");
+        break;
+
+      case FN_FPMIN:
+        printf("\\ffpminimum(f1,f2,d)\n\
+  f1,f2 = floating-point numbers or integers.\n\
+      d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The minimum of f1 and f2 to d decimal places.\n");
+        break;
+
+      case FN_FPMOD:
+        printf("\\ffpmodulus(f1,f2,d)\n\
+  f1,f2 = floating-point numbers or integers.\n\
+      d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The modulus of f1 and f2 to d decimal places.\n");
+        break;
+
+      case FN_FPPOW:
+        printf("\\ffpraise(f1,f2,d)\n\
+  f1,f2 = floating-point numbers or integers.\n\
+      d = integer.\n");
+        printf("Returns floating-point number:\n\
+  f1 raised to the power f2, to d decimal places.\n");
+        break;
+
+      case FN_FPCOS:
+        printf("\\ffpcosine(f1,d)\n\
+  f1 = floating-point number or integer.\n\
+   d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The cosine of angle f1 (in radians) to d decimal places.\n");
+        break;
+
+      case FN_FPSIN:
+        printf("\\ffpsine(f1,d)\n\
+  f1 = floating-point number or integer.\n\
+   d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The sine of angle f1 (in radians) to d decimal places.\n");
+        break;
+
+      case FN_FPTAN:
+        printf("\\ffptangent(f1,d)\n\
+  f1 = floating-point number or integer.\n\
+   d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The tangent of angle f1 (in radians) to d decimal places.\n");
+        break;
+
+      case FN_FPEXP:
+        printf("\\ffpexp(f1,d)\n\
+  f1 = floating-point number or integer.\n\
+   d = integer.\n");
+        printf("Returns floating-point number:\n\
+  e (the base of natural logarithms) raised to the f1 power,\n\
+  to d decimal places.\n");
+        break;
+
+      case FN_FPINT:
+        printf("\\ffpint(f1)\n\
+  f1 = floating-point number or integer.\n");
+        printf("Returns integer:\n\
+  The integer part of f1.\n");
+        break;
+
+      case FN_FPLOG:
+        printf("\\ffplog10(f1,d)\n\
+  f1 = floating-point number or integer.\n\
+   d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The logarithm, base 10, of f1 to d decimal places.\n");
+        break;
+
+      case FN_FPLN:
+        printf("\\ffplogn(f1,d)\n\
+  f1 = floating-point number or integer.\n\
+   d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The natural logarithm of f1 to d decimal places.\n");
+        break;
+
+      case FN_FPROU:
+        printf("\\ffpround(f1,d)\n\
+  f1 = floating-point number or integer.\n\
+   d = integer.\n");
+        printf("Returns floating-point number:\n\
+  f1 rounded to d decimal places.\n");
+        break;
+
+      case FN_FPSQR:
+        printf("\\ffpsqrt(f1,d)\n\
+  f1 = floating-point number or integer.\n\
+   d = integer.\n");
+        printf("Returns floating-point number:\n\
+  The square root of f1 to d decimal places.\n");
+        break;
+#endif /* FNFLOAT */
+
+#ifdef CKCHANNELIO
+      case FN_FEOF:
+        printf("\\f_eof(n1)\n\
+  n1 = channel number.\n");
+        printf("Returns number:\n\
+  1 if channel n1 at end of file, 0 otherwise.\n");
+        break;
+      case FN_FPOS:
+        printf("\\f_pos(n1)\n\
+  n1 = channel number.\n");
+        printf("Returns number:\n\
+  Read/write pointer of channel n1 as byte number.\n");
+        break;
+      case FN_NLINE:
+        printf("\\f_line(n1)\n\
+  n1 = channel number.\n");
+        printf("Returns number:\n\
+  Read/write pointer of channel n1 as line number.\n");
+        break;
+      case FN_FILNO:
+        printf("\\f_handle(n1)\n\
+  n1 = channel number.\n");
+        printf("Returns number:\n\
+  File %s of open file on channel n1.\n",
+#ifdef OS2
+               "handle"
+#else
+               "descriptor"
+#endif /* OS2 */
+               );
+        break;
+      case FN_FSTAT:
+        printf("\\f_status(n1)\n\
+  n1 = channel number.\n");
+        printf("Returns number:\n\
+  Sum of open modes of channel n1: 1 = read; 2 = write; 4 = append, or:\n\
+  0 if not open.\n");
+        break;
+      case FN_FGCHAR:
+        printf("\\f_getchar(n1)\n\
+  n1 = channel number.\n");
+        printf("  Reads a character from channel n1 and returns it.\n");
+        break;
+      case FN_FGLINE:
+        printf("\\f_getline(n1)\n\
+  n1 = channel number.\n");
+        printf("  Reads a line from channel n1 and returns it.\n");
+        break;
+      case FN_FGBLK:
+        printf("\\f_getblock(n1,n2)\n\
+  n1 = channel number, n2 = size\n");
+        printf(
+"  Reads a block of n2 characters from channel n1 and returns it.\n");
+        break;
+      case FN_FPCHAR:
+        printf("\\f_putchar(n1,c)\n\
+  n1 = channel number, c = character\n");
+        printf("  Writes a character to channel n1.\n\
+Returns number:\n\
+  1 if successful, otherwise a negative error code.\n");
+        break;
+      case FN_FPLINE:
+        printf("\\f_putline(n1,s1)\n\
+  n1 = channel number, s1 = string\n");
+        printf(
+"  Writes the string s1 to channel n1 and adds a line terminator.\n\
+Returns number:\n");
+        printf("  How many characters written if successful;\n\
+  Otherwise a negative error code.\n"
+               );
+        break;
+      case FN_FPBLK:
+        printf("\\f_putblock(n1,s1)\n\
+  n1 = channel number, s1 = string\n");
+        printf(
+"  Writes the string s1 to channel n1.\n\
+  Returns number:\n");
+        printf("  How many characters written if successful;\n\
+  Otherwise a negative error code.\n"
+               );
+        break;
+      case FN_FERMSG:
+        printf("\\f_errmsg([n1])\n\
+  n1 = numeric error code, \\v(f_error) by default.\n");
+        printf("  Returns the associated error message string.\n");
+        break;
+#endif /* CKCHANNELIO */
+
+      case FN_AADUMP:
+        printf("\\faaconvert(name,&a[,&b])\n\
+  name = name of associative array, &a and &b = names of regular arrays.\n");
+        printf(
+"  Converts the given associative array into two regular arrays, &a and &b,\n\
+  containing the indices and values, respectively:\n");
+        printf("Returns number:\n\
+  How many elements were converted.\n");
+        break;
+
+#ifdef CK_KERBEROS
+      case FN_KRB_TK:
+        printf("\\fkrbtickets(n)\n\
+  n = Kerberos version number (4 or 5).\n\
+  Returns string:\n\
+  The number of active Kerberos 4 or 5 tickets.\n\
+  Resets the ticket list used by \\fkrbnextticket(n).\n");
+        break;
+
+      case FN_KRB_NX:
+        printf("\\fkrbnextticket(n)\n\
+  n = Kerberos version number (4 or 5).\n\
+  Returns string:\n\
+    The next ticket in the Kerberos 4 or 5 ticket list that was set up by\n\
+    the most recent invocation of \\fkrbtickets(n).\n");
+        break;
+
+      case FN_KRB_IV:
+        printf("\\fkrbisvalid(n,name)\n\
+  n    = Kerberos version number (4 or 5).\n\
+  name = a ticket name as returned by \\fkrbnextticket(n).\n\
+  Returns number:\n\
+    1 if the ticket is valid, 0 if not valid.\n\
+    A ticket is valid if all the following conditions are true:\n\n");
+        printf("\n\
+    (i)   it exists in the current cache file;\n\
+    (ii)  it is not expired;\n\
+    (iii) it is not marked invalid (K5 only);\n\
+    (iv)  it was issued from the current IP address\n");
+        printf("\n  This value can be used in an IF statement, e.g.:\n\n");
+        printf("    if \\fkrbisvalid(4,krbtgt.FOO.BAR.EDU@FOO.BAR.EDU) ...\n");
+        break;
+
+      case FN_KRB_TT:
+        printf("\\fkrbtimeleft(n,name)\n\
+  n    = Kerberos version number (4 or 5).\n\
+  name = a ticket name as returned by \\fkrbnextticket(n).\n\
+  Returns string:\n\
+    The number of seconds remaining in the ticket's lifetime.\n");
+        break;
+
+      case FN_KRB_FG:
+        printf("\\fkrbflags(n,name)\n\
+  n    = Kerberos version number (4 or 5).\n\
+  name = a ticket name as returned by \\fkrbnextticket(n).\n\
+  Returns string:\n");
+        printf(
+"    The flags string as reported with AUTH K5 LIST /FLAGS.  This string can\n\
+    be searched for a particular flag using the \\findex() function when\n\
+    SET CASE is ON (for case sensitive searches).  Flag strings are only\n\
+    available for K5 tickets.\n");
+        break;
+#endif /* CK_KERBEROS */
+
+      case FN_PATTERN:
+        printf("\\fpattern(s)\n\
+  s = string\n\
+  Returns string: s with any variables, etc, evaluated in the normal manner.\n"
+               );
+        printf("\
+  For use with INPUT, MINPUT, and REINPUT to declare that a search target is\n\
+  a pattern rather than a literal string.\n");
+        break;
+
+      case FN_HEX2N:
+        printf("\\fhex2n(s)\n\
+  s = hexadecimal number\n\
+  Returns decimal equivalent.\n");
+        break;
+
+      case FN_HEX2IP:
+        printf("\\fhex2ip(s)\n\
+  s = 8-digit hexadecimal number\n\
+  Returns the equivalent decimal dotted IP address.\n");
+        break;
+
+      case FN_IP2HEX:
+        printf("\\fip2hex(s)\n\
+  s = decimal dotted IP address\n\
+  Returns the equivalent 8-digit hexadecimal number.\n");
+        break;
+
+      case FN_OCT2N:
+        printf("\\foct2n(s)\n\
+  s = octal number\n\
+  Returns decimal equivalent.\n");
+        break;
+
+      case FN_RADIX:
+        printf("\\fradix(s,n1,n2)\n\
+  s = number in radix n1\n\
+  Returns the number's representation in radix n2.\n");
+        break;
+
+      case FN_JOIN:
+        printf("\\fjoin(&a[,s[,n1[,n2]]])\n\
+  &a = array designator, can include range specifier.\n\
+  s  = optional separator.\n");
+        printf("\
+  n1 = nonzero to put grouping around elements that contain spaces;\n\
+       see \\fword() grouping mask for values of n.\n");
+        printf("\
+  n2 = 0 or omitted to put spaces between elements; nonzero to omit them.\n");
+        printf("\
+  Returns the (selected) elements of the array joined to together,\n\
+  separated by the separator.\n");
+        break;
+
+      case FN_SUBST:
+        printf("\\fsubstitute(s1,s2,s3)\n\
+  s1 = Source string.\n\
+  s2 = List of characters to be translated.\n\
+  s3 = List of characters to translate them to.\n");
+        printf(
+"  Returns: s1, with each character that is in s2 translated to the\n\
+  corresponding character in s3.  s2 and s3 can contain ASCII ranges,\n\
+  like [a-z].  Any characters in s2 that don't have corresponding\n\
+  characters in s3 (after range expansion) are removed from the result.\n");
+        break;
+
+#ifndef NOSEXP
+      case FN_SEXP:
+        printf("\\fsexpression(s1)\n\
+  s1 = S-Expression.\n");
+        printf("  Returns: The result of evaluating s1.\n");
+        break;
+
+#endif /* NOSEXP */
+
+      case FN_CMDSTK:
+        printf("\\fcmdstack(n1,n2)\n\
+  n1 = Command-stack level, 0 to \\v(cmdlevel), default \\v(cmdlevel).\n\
+  n2 = Function code, 0 or 1.\n");
+        printf("Returns:\n");
+        printf("  n2 = 0: name of object at stack level n1\n\
+  n2 = 1: type of object at stack level n1:\n\
+     0 = interactive prompt\n\
+     1 = command file\n\
+     2 = macro\n"
+               );
+          break;
+
+#ifdef CKFLOAT
+      case FN_DIFDATE:
+        printf("\\fdiffdates(d1,d2)\n\
+  d1 = free-format date and/or time (default = NOW).\n\
+  d2 = ditto.\n");
+        printf("Returns:\n");
+        printf("  Difference expressed as delta time:\n");
+        printf("  Negative if d2 is later than d1, otherwise positive.\n");
+        break;
+#endif /* CKFLOAT */
+
+      case FN_CMPDATE:
+        printf("\\fcmpdates(d1,d2)\n\
+  d1 = free-format date and/or time (default = NOW).\n\
+  d2 = ditto.\n");
+        printf("Returns:\n");
+        printf("  0 if d1 is equal to d2;\n\
+  1 if d1 is later than d2;\n\
+ -1 if d1 is earlier than d2.\n");
+        break;
+
+      case FN_TOGMT:
+        printf("\\futcdate(d1)\n\
+  d1 = free-format date and/or time (default = NOW).\n");
+        printf("Returns:\n");
+        printf("  Date-time converted to UTC (GMT) yyyymmdd hh:mm:ss.\n");
+        break;
+
+#ifdef TCPSOCKET
+      case FN_HSTADD:
+        printf("\\faddr2name(s)\n\
+  s = numeric IP address.\n");
+        printf("Returns:\n");
+        printf("  Corresponding IP hostname if found, otherwise null.\n");
+        break;
+      case FN_HSTNAM:
+        printf("\\fname2addr(s)\n\
+  s = IP host name.\n");
+        printf("Returns:\n");
+        printf("  Corresponding numeric IP address if found, else null.\n");
+        break;
+#endif /* TCPSOCKET */
+
+      case FN_DELSEC:
+        printf("\\fdelta2secs(dt)\n\
+  dt = Delta time, e.g. +3d14:27:52.\n");
+        printf("Returns:\n");
+        printf("  The corresponding number of seconds.\n");
+        break;
+
+      case FN_PC_DU:
+        printf("\\fdos2unixpath(p)\n\
+  p = string, DOS pathname.\n");
+        printf("Returns:\n");
+        printf("  The argument converted to a Unix pathname.\n");
+        break;
+
+      case FN_PC_UD:
+        printf("\\funix2dospath(p)\n\
+  p = string, Unix pathname.\n");
+        printf("Returns:\n");
+        printf("  The argument converted to a DOS pathname.\n");
+        break;
+
+#ifdef FN_ERRMSG
+      case FN_ERRMSG:
+        printf("\\ferrstring(n)\n\
+  n = platform-dependent numeric error code.\n");
+        printf("Returns:\n");
+        printf("  The corresponding error string.\n");
+        break;
+#endif /* FN_ERRMSG */
+
+      case FN_KWVAL:
+        printf("\\fkeywordvalue(s1,c1)\n\
+  s1 = string of the form \"name=value\"\n\
+  c1 = separator character (default separator is \"=\")\n");
+        printf("    Assigns the value, if any, to the named macro.\n");
+        printf("    If s1 contains no separator, nothing happens.\n");
+        printf(
+"    If s1 contains a separator but no value, the macro is undefined.\n");
+        printf("Returns:\n");
+        printf("  0 on failure\n");
+        printf("  1 on success\n");
+        break;
+
+#ifdef COMMENT
+      case FN_SLEEP:
+        printf("\\fsleep(n)\n\
+  n = number of seconds\n");
+        printf("    Pauses for the given number of seconds.\n");
+        printf("Returns: the empty string.\n");
+        break;
+
+      case FN_MSLEEP:
+        printf("\\fmsleep(n)\n\
+  n = number of milliseconds\n");
+        printf("    Pauses for the given number of milliseconds.\n");
+        printf("Returns: the empty string.\n");
+        break;
+#endif /* COMMENT */
+
+#ifdef NT
+      case FN_SNAME:
+        printf("\\fshortpathname(s)\n\
+  s = file or directory name string\n");
+        printf("    Returns the short path form of the given input.\n");
+        break;
+
+      case FN_LNAME:
+        printf("\\flongpathname(s)\n\
+  s = file or directory name string\n");
+        printf("    Returns the long path form of the given input.\n");
+        break;
+#else
+      case FN_SNAME:
+        printf("\\fshortpathname(s)\n\
+    Synonym for \fpathname()\n");
+        break;
+
+      case FN_LNAME:
+        printf("\\flongpathname(s)\n\
+    Synonym for \fpathname()\n");
+        break;
+#endif /* NT */
+
+      default:
+        printf("Sorry, help not available for \"%s\"\n",cmdbuf);
+    }
+   printf("\n");
+   return(0);
+}
+#endif /* NOSPL */
+
+#ifdef OS2
+#ifndef NOKVERBS
+
+/*  D O H K V E R B  --  Give help for a Kverb  */
+
+int
+dohkverb(xx) int xx; {
+    int x,i,found,button,event;
+
+    if (xx == -3) {
+        printf("\n Type SHOW KVERBS to see a list of available Kverbs.\n"
+               );
+        printf(
+" Type HELP KVERB <name> to see the current definition of a given Kverb.\n\n"
+              );
+        return(-9);
+    }
+    if (xx < 0) return(xx);
+    if ((x = cmcfm()) < 0) return(x);
+    switch ( xx ) {
+        /* DEC VT keyboard key definitions */
+
+    case  K_COMPOSE :                   /* Compose key */
+        printf("\\Kcompose           Compose an accented character\n");
+        break;
+    case  K_C_UNI16 :                   /* UCS2 key */
+        printf("\\Kucs2              Enter a Unicode character\n");
+        break;
+
+/* DEC arrow keys */
+
+    case  K_UPARR     :                 /* DEC Up Arrow key */
+        printf("\\Kuparr         Transmit Terminal Up Arrow sequence\n");
+        break;
+    case  K_DNARR     :                 /* DEC Down Arrow key */
+        printf("\\Kdnarr         Transmit Terminal Down Arrow sequence\n");
+        break;
+    case  K_RTARR     :                 /* DEC Right Arrow key */
+        printf("\\Krtarr         Transmit Terminal Right Arrow sequence\n");
+        break;
+    case  K_LFARR     :                 /* DEC Left Arrow key */
+        printf("\\Klfarr         Transmit Terminal Left Arrow sequence\n");
+        break;
+
+    case  K_PF1       :                 /* DEC PF1 key */
+        printf("\\Kpf1,\\Kgold    Transmit DEC PF1 sequence\n");
+        break;
+    case  K_PF2       :                 /* DEC PF2 key */
+        printf("\\Kpf2           Transmit DEC PF2 sequence\n");
+        break;
+    case  K_PF3       :                 /* DEC PF3 key */
+        printf("\\Kpf3           Transmit DEC PF3 sequence\n");
+        break;
+    case  K_PF4       :                 /* DEC PF4 key */
+        printf("\\Kpf4           Transmit DEC PF4 sequence\n");
+        break;
+
+    case  K_KP0       :                 /* DEC Keypad 0 */
+        printf("\\Kkp0           Transmit DEC Keypad-0 sequence\n");
+        break;
+    case  K_KP1       :                 /* DEC Keypad 1 */
+        printf("\\Kkp1           Transmit DEC Keypad-1 sequence\n");
+        break;
+    case  K_KP2       :                 /* etc ... through 9 */
+        printf("\\Kkp2           Transmit DEC Keypad-2 sequence\n");
+        break;
+    case  K_KP3       :
+        printf("\\Kkp3           Transmit DEC Keypad-3 sequence\n");
+        break;
+    case  K_KP4       :
+        printf("\\Kkp4           Transmit DEC Keypad-4 sequence\n");
+        break;
+    case  K_KP5       :
+        printf("\\Kkp5           Transmit DEC Keypad-5 sequence\n");
+        break;
+    case  K_KP6       :
+        printf("\\Kkp6           Transmit DEC Keypad-6 sequence\n");
+        break;
+    case  K_KP7       :
+        printf("\\Kkp7           Transmit DEC Keypad-7 sequence\n");
+        break;
+    case  K_KP8       :
+        printf("\\Kkp8           Transmit DEC Keypad-8 sequence\n");
+        break;
+    case  K_KP9       :
+        printf("\\Kkp9           Transmit DEC Keypad-9 sequence\n");
+        break;
+    case  K_KPCOMA    :                 /* DEC keypad comma */
+        printf("\\Kkpcoma        Transmit DEC Keypad-Comma sequence\n");
+        break;
+    case  K_KPMINUS   :                 /* DEC keypad minus */
+        printf("\\Kkpminus       Transmit DEC Keypad-Minus sequence\n");
+        break;
+    case  K_KPDOT     :                 /* DEC keypad period */
+        printf("\\Kkpdot         Transmit DEC Keypad-Period sequence\n");
+        break;
+    case  K_KPENTER   :                 /* DEC keypad enter */
+        printf("\\Kkpenter       Transmit DEC Keypad-Enter sequence\n");
+        break;
+
+/* DEC Top-Rank F keys */
+
+    case  K_DECF1     :                 /* DEC F1 key */
+        printf("\\Kdecf1         Transmit DEC F1 sequence for PC keyboard\n");
+        break;
+    case  K_DECF2     :                 /* DEC F2 key */
+        printf("\\Kdecf2         Transmit DEC F2 sequence for PC keyboard\n");
+        break;
+    case  K_DECF3     :                 /* DEC F3 key */
+        printf("\\Kdecf3         Transmit DEC F3 sequence for PC keyboard\n");
+        break;
+    case  K_DECF4     :                 /* DEC F4 key */
+        printf("\\Kdecf4         Transmit DEC F4 sequence for PC keyboard\n");
+        break;
+    case  K_DECF5     :                 /* DEC F5 key */
+        printf("\\Kdecf5         Transmit DEC F5 sequence for PC keyboard\n");
+        break;
+    case  K_DECHOME:                    /* DEC HOME key */
+       printf("\\Kdechome       Transmit DEC HOME sequence for PC keyboard\n");
+       break;
+
+    case  K_DECF6     :                 /* DEC F6 key */
+        printf("\\Kdecf6         Transmit DEC F6 sequence\n");
+        break;
+    case  K_DECF7     :                 /* etc, through F20 */
+        printf("\\Kdecf7         Transmit DEC F7 sequence\n");
+        break;
+    case  K_DECF8     :
+        printf("\\Kdecf8         Transmit DEC F8 sequence\n");
+        break;
+    case  K_DECF9     :
+        printf("\\Kdecf9         Transmit DEC F9 sequence\n");
+        break;
+    case  K_DECF10    :
+        printf("\\Kdecf10        Transmit DEC F10 sequence\n");
+        break;
+    case  K_DECF11    :
+        printf("\\Kdecf11        Transmit DEC F11 sequence\n");
+        break;
+    case  K_DECF12    :
+        printf("\\Kdecf12        Transmit DEC F12 sequence\n");
+        break;
+    case  K_DECF13    :
+        printf("\\Kdecf13        Transmit DEC F13 sequence\n");
+        break;
+    case  K_DECF14    :
+        printf("\\Kdecf14        Transmit DEC F14 sequence\n");
+        break;
+    case  K_DECHELP   :                 /* DEC Help key */
+        printf("\\Kdecf15,\\Kdechelp  Transmit DEC HELP sequence\n");
+        break;
+    case  K_DECDO     :                 /* DEC Do key */
+        printf("\\Kdecf16,\\Kdecdo    Transmit DEC DO sequence\n");
+        break;
+    case  K_DECF17    :
+        printf("\\Kdecf17        Transmit DEC F17 sequence\n");
+        break;
+    case  K_DECF18    :
+        printf("\\Kdecf18        Transmit DEC F18 sequence\n");
+        break;
+    case  K_DECF19    :
+        printf("\\Kdecf19        Transmit DEC F19 sequence\n");
+        break;
+    case  K_DECF20    :
+        printf("\\Kdecf20        Transmit DEC F20 sequence\n");
+        break;
+
+/* DEC editing keys */
+
+    case  K_DECFIND   :                 /* DEC Find key */
+        printf("\\Kdecfind       Transmit DEC FIND sequence\n");
+        break;
+    case  K_DECINSERT :                 /* DEC Insert key */
+        printf("\\Kdecinsert     Transmit DEC INSERT HERE sequence\n");
+        break;
+    case  K_DECREMOVE :                 /* DEC Remove key */
+        printf("\\Kdecremove     Transmit DEC REMOVE sequence\n");
+        break;
+    case  K_DECSELECT :                 /* DEC Select key */
+        printf("\\Kdecfselect    Transmit DEC SELECT sequence\n");
+        break;
+    case  K_DECPREV   :                 /* DEC Previous Screen key */
+        printf("\\Kdecprev       Transmit DEC PREV SCREEN sequence\n");
+        break;
+    case  K_DECNEXT   :                 /* DEC Next Screen key */
+        printf("\\Kdecnext       Transmit DEC NEXT SCREEN sequence\n");
+        break;
+
+/* DEC User-Defined Keys */
+
+    case  K_UDKF1     :                 /* F1 - F5 are XTERM extensions */
+      printf("\\Kudkf1         Transmit XTERM F1 User Defined Key sequence\n");
+      break;
+    case  K_UDKF2     :
+      printf("\\Kudkf2         Transmit XTERM F2 User Defined Key sequence\n");
+      break;
+    case  K_UDKF3     :
+      printf("\\Kudkf3         Transmit XTERM F3 User Defined Key sequence\n");
+      break;
+    case  K_UDKF4     :
+      printf("\\Kudkf4         Transmit XTERM F4 User Defined Key sequence\n");
+      break;
+    case  K_UDKF5     :
+      printf("\\Kudkf5         Transmit XTERM F5 User Defined Key sequence\n");
+      break;
+    case  K_UDKF6     :                 /* DEC User Defined Key F6 */
+      printf("\\Kudkf6         Transmit DEC F6 User Defined Key sequence\n");
+      break;
+    case  K_UDKF7     :                 /* DEC User Defined Key F7 */
+      printf("\\Kudkf7         Transmit DEC F7 User Defined Key sequence\n");
+      break;
+    case  K_UDKF8     :                 /* etc ... through F20 */
+      printf("\\Kudkf8         Transmit DEC F8 User Defined Key sequence\n");
+      break;
+    case  K_UDKF9     :
+      printf("\\Kudkf9         Transmit DEC F9 User Defined Key sequence\n");
+      break;
+    case  K_UDKF10    :
+      printf("\\Kudkf10        Transmit DEC F10 User Defined Key sequence\n");
+      break;
+    case  K_UDKF11    :
+      printf("\\Kudkf11        Transmit DEC F11 User Defined Key sequence\n");
+      break;
+    case  K_UDKF12    :
+      printf("\\Kudkf12        Transmit DEC F12 User Defined Key sequence\n");
+      break;
+    case  K_UDKF13    :
+      printf("\\Kudkf13        Transmit DEC F13 User Defined Key sequence\n");
+      break;
+    case  K_UDKF14    :
+      printf("\\Kudkf14        Transmit DEC F14 User Defined Key sequence\n");
+      break;
+    case  K_UDKHELP   :
+      printf(
+      "\\Kudkhelp,\\Kudkf15  Transmit DEC HELP User Defined Key sequence\n");
+      break;
+    case  K_UDKDO     :
+      printf(
+      "\\Kudkdo,\\Kudkf16    Transmit DEC DO User Defined Key sequence\n");
+      break;
+    case  K_UDKF17    :
+      printf("\\Kudkf17        Transmit DEC F17 User Defined Key sequence\n");
+      break;
+    case  K_UDKF18    :
+      printf("\\Kudkf18        Transmit DEC F18 User Defined Key sequence\n");
+      break;
+    case  K_UDKF19    :
+      printf("\\Kudkf19        Transmit DEC F19 User Defined Key sequence\n");
+      break;
+    case  K_UDKF20    :
+      printf("\\Kudkf20        Transmit DEC F20 User Defined Key sequence\n");
+      break;
+
+/* Emacs Keys */
+    case  K_EMACS_OVER:
+      printf(
+     "\\Kemacs_overwrite  Transmit EMACS Overwrite toggle command sequence\n");
+      break;
+
+/* Kermit screen-scrolling keys */
+
+    case  K_DNONE     :                 /* Screen rollback: down one line */
+      printf("\\Kdnone         Screen rollback: down one line\n");
+      break;
+    case  K_DNSCN     :                 /* Screen rollback: down one screen */
+      printf("\\Kdnscn         Screen rollback: down one screen\n");
+      break;
+    case  K_UPONE     :                 /* Screen rollback: Up one line */
+      printf("\\Kupone         Screen rollback: up one line\n");
+      break;
+    case  K_UPSCN     :                 /* Screen rollback: Up one screen */
+      printf("\\Kupscn         Screen rollback: up one screen\n");
+      break;
+    case  K_ENDSCN    :                 /* Screen rollback: latest screen */
+      printf("\\Kendscn        Screen rollback: latest screen\n");
+      break;
+    case  K_HOMSCN    :                 /* Screen rollback: oldest screen */
+      printf("\\Khomscn        Screen rollback: oldest screen\n");
+      break;
+    case  K_GO_BOOK   :         /* Scroll to bookmark */
+      printf("\\Kgobook        Screen rollback: go to bookmark\n");
+      break;
+    case  K_GOTO      :         /* Scroll to line number */
+      printf("\\Kgoto          Screen rollback: go to line number\n");
+      break;
+
+    case  K_LFONE     :                 /* Horizontal Scroll: Left one cell */
+      printf("\\Klfone         Horizontal Scroll: Left one column\n");
+      break;
+    case  K_LFPAGE    :                 /* Horizontal Scroll: Left one page */
+      printf("\\Klfpage        Horizontal Scroll: Left eight columns\n");
+      break;
+    case  K_LFALL     :
+      printf("\\Klfall         Horizontal Scroll: Left to margin\n");
+      break;
+    case  K_RTONE     :                 /* Horizontal Scroll: Right one cell */
+      printf("\\Krtone         Horizontal Scroll: Right one column\n");
+      break;
+    case  K_RTPAGE    :                 /* Horizontal Scroll: Right one page */
+      printf("\\Krtpage        Horizontal Scroll: Right eight columns\n");
+      break;
+    case  K_RTALL     :
+      printf("\\Krtall         Horizontal Scroll: Right to margin\n");
+      break;
+
+/* Keyboard language switching verbs */
+
+    case  K_KB_ENG    :                 /* English keyboard mode */
+      printf("\\Kkbenglish     Switch to Normal (English) keyboard mode\n");
+      break;
+    case  K_KB_HEB    :                 /* Hebrew keyboard mode */
+      printf("\\Kkbhebrew      Switch to Hebrew keyboard mode\n");
+      break;
+    case  K_KB_RUS    :                 /* Russian keyboard mode */
+      printf("\\Kkbrussian     Switch to Russian keyboard mode\n");
+      break;
+    case  K_KB_EMA    :                 /* Emacs keyboard mode */
+      printf("\\Kkbemacs       Switch to EMACS keyboard mode\n");
+      break;
+    case  K_KB_WP     :                 /* Word Perfect 5.1 mode */
+      printf("\\Kkbwp          Switch to Word Perfect 5.1 keyboard mode\n");
+      break;
+
+/* Mark Mode actions */
+
+    case  K_MARK_START  :       /* Enter Mark Mode/Start marking */
+      printf("\\Kmarkstart     Mark Mode: Enter mode or Start marking\n");
+      break;
+    case  K_MARK_CANCEL :       /* Exit Mark Mode - Do Nothing */
+      printf("\\Kmarkcancel    Mark Mode: Cancel mode\n");
+      break;
+    case  K_MARK_COPYCLIP:      /* Exit Mark Mode - Copy data to clipboard */
+      printf("\\Kmarkcopyclip  Mark Mode: Copy marked text to clipboard\n");
+      break;
+    case  K_MARK_COPYHOST:      /* Exit Mark Mode - Copy data to host   */
+      printf("\\Kmarkcopyhost  Mark Mode: Copy marked text to host\n");
+      break;
+    case  K_MARK_SELECT :       /* Exit Mark Mode - Select */
+      printf(
+      "\\Kmarkselect    Mark Mode: Place marked text into \\v(select)\n");
+      break;
+    case  K_BACKSRCH    :            /* Search Backwards for text */
+      printf("\\Kbacksearch    Search: Begin backward search for text\n");
+      break;
+    case  K_FWDSRCH     :            /* Search Forwards for text */
+      printf("\\Kfwdsearch     Search: Begin forward search for text\n");
+      break;
+    case  K_BACKNEXT    :     /* Search Backwards for next instance of text */
+      printf(
+      "\\Kbacknext      Search: Find next instance of text backwards\n");
+      break;
+    case  K_FWDNEXT     :      /* Search Forwards for next instance of text */
+      printf("\\Kfwdnext       Search: Find next instance of text forwards\n");
+      break;
+
+/* Miscellaneous Kermit actions */
+
+    case  K_EXIT        :               /* Return to command parser */
+      printf("\\Kexit          Toggle between COMMAND and CONNECT modes\n");
+      break;
+    case  K_BREAK       :               /* Send a BREAK */
+      printf("\\Kbreak         Transmit BREAK signal to host\n");
+      break;
+    case  K_RESET       :               /* Reset emulator */
+      printf("\\Kreset         Reset Terminal Emulator to user defaults\n");
+      break;
+    case  K_DOS         :               /* Push to DOS (i.e. OS/2) */
+      printf("\\Kdos,\\Kos2     Push to Command Shell\n");
+      break;
+    case  K_HANGUP      :               /* Hang up the connection */
+      printf("\\Khangup        Hangup the active connection\n");
+      break;
+    case  K_DUMP        :               /* Dump/Print current screen */
+      printf(
+     "\\Kdump          Dump/copy current screen to SET PRINTER device/file\n");
+      break;
+    case  K_LBREAK      :               /* Send a Long BREAK */
+      printf("\\Klbreak        Transmit LONG BREAK signal to host\n");
+      break;
+    case  K_NULL        :               /* Send a NUL */
+      printf("\\Knull          Transmit NULL ('\0') character to host\n");
+      break;
+    case  K_HELP        :               /* Pop-up help */
+      printf("\\Khelp          Raise Pop-Up help display\n");
+      break;
+    case  K_HOLDSCRN    :               /* Hold screen */
+      printf("\\Kholdscrn      Pause data input during CONNECT mode\n");
+      break;
+    case  K_IGNORE      :               /* Ignore this key, don't even beep */
+      printf("\\Kignore        Ignore key\n");
+      break;
+
+    case  K_LOGOFF      :               /* Turn off session logging */
+      printf("\\Klogoff        Turn off session logging (see \\Ksession)\n");
+      break;
+    case  K_LOGON       :               /* Turn on session logging */
+      printf("\\Klogon         Turn on session logging (see \\Ksession)\n");
+      break;
+    case K_SESSION:
+      printf(
+         "\\Ksession       Toggle on/off session logging to 'session.log'\n");
+      break;
+    case K_AUTODOWN:
+      printf("\\Kautodown      Toggle on/off terminal autodownload.\n");
+      break;
+    case K_BYTESIZE:
+      printf(
+        "\\Kbytesize      Toggle terminal bytesize between 7 and 8 bits.\n");
+      break;
+
+#ifdef COMMENT
+    case MODELINE:
+    case  K_NETHOLD     :               /* Put network connection on hold */
+    case  K_NEXTSESS    :               /* Toggle to next network session */
+#endif /* COMMENT */
+
+    case K_CURSOR_URL:
+        printf(
+     "\\Kurl           Treat text under cursor position as a URL\n");
+        break;
+    case  K_STATUS      :               /* Show status */
+      printf(
+     "\\Kstatus        Toggle statusline (None, Indicator, Host Writeable)\n");
+      break;
+    case  K_TERMTYPE    :               /* Toggle term type: text/graphics */
+      printf("\\Ktermtype      Toggle Terminal Type\n");
+      break;
+    case  K_PRTCTRL     :               /* Print Controller mode */
+      printf("\\Kprtctrl       Toggle Ctrl-Print (transparent) mode\n");
+      break;
+    case  K_PRINTFF     :               /* Print formfeed */
+      printf("\\Kprintff       Output Form Feed to SET PRINTER device\n");
+      break;
+    case  K_FLIPSCN     :               /* Flip screen */
+      printf("\\Kflipscn       Reverse foreground and background colors\n");
+      break;
+    case  K_DEBUG       :               /* Toggle debugging */
+      printf("\\Kdebug         Toggle Terminal Debug mode\n");
+      break;
+    case  K_TN_SAK      :               /* TELNET Secure Access Key */
+      printf("\\Ktn_sak        TELNET: IBM Secure Access Key\n");
+      printf("                Used to request a Trusted Shell with AIX\n");
+      break;
+    case  K_TN_AO       :               /* TELNET Cancel Output */
+      printf("\\Ktn_ao         TELNET: Transmit Cancel-Output request\n");
+      break;
+    case  K_TN_AYT      :               /* TELNET Are You There */
+      printf("\\Ktnayt         TELNET: Transmit Are You There? request\n");
+      break;
+    case  K_TN_EC       :               /* TELNET Erase Character */
+      printf("\\Ktn_ec         TELNET: Transmit Erase Character request\n");
+      break;
+    case  K_TN_EL       :               /* TELNET Erase Line */
+      printf("\\Ktn_el         TELNET: Transmit Erase Line request\n");
+      break;
+    case  K_TN_GA       :               /* TELNET Go Ahead */
+      printf("\\Ktn_ga         TELNET: Transmit Go Ahead request\n");
+      break;
+    case  K_TN_IP       :               /* TELNET Interrupt Process */
+      printf("\\Ktn_ip         TELNET: Transmit Interrupt Process request\n");
+      break;
+    case  K_TN_LOGOUT   :               /* TELNET Logout */
+      printf("\\Ktn_logout     TELNET: Transmit Do Logout Option\n");
+      break;
+    case  K_TN_NAWS   :                 /* TELNET NAWS */
+      printf(
+        "\\Ktn_naws       TELNET: Transmit Window Size if NAWS is active\n");
+      break;
+    case  K_PASTE       :               /* Paste data from clipboard */
+      printf("\\Kpaste         Paste data from clipboard to host\n");
+      break;
+    case  K_CLRSCRN     :               /* Clear Terminal Screen */
+      printf("\\Kclearscreen   Clear the Terminal screen\n");
+      break;
+    case  K_PRTAUTO     :               /* Print Auto mode */
+      printf("\\Kprtauto       Toggle Auto-Print mode\n");
+      break;
+    case  K_PRTCOPY     :               /* Print Copy mode */
+      printf("\\Kprtcopy       Toggle Copy-Print mode\n");
+      break;
+    case  K_ANSWERBACK  :               /* Transmit Answerback String */
+      printf("\\Kanswerback    Transmit answerback string to host\n");
+      break;
+    case  K_SET_BOOK    :               /* Set Bookmark */
+      printf("\\Ksetbook       Set bookmark\n");
+      break;
+    case  K_QUIT        :               /* Quit Kermit */
+      printf("\\Kquit          Hangup connection and quit kermit\n");
+      break;
+    case  K_KEYCLICK    :               /* Toggle Keyclick */
+      printf("\\Kkeyclick      Toggle Keyclick mode\n");
+      break;
+    case  K_LOGDEBUG    :               /* Toggle Debug Log File */
+      printf("\\Klogdebug      Toggle Debug Logging to File\n");
+      break;
+    case  K_FNKEYS      :               /* Show Function Key Labels */
+      printf("\\Kfnkeys        Display Function Key Labels\n");
+      break;
+
+#ifdef OS2MOUSE
+/* Mouse only Kverbs */
+
+    case  K_MOUSE_CURPOS :
+      printf("\\Kmousecurpos   Mouse: Move host cursor to position\n");
+      break;
+    case  K_MOUSE_MARK   :
+      printf(
+     "\\Kmousemark     Mouse: Mark text for selection (drag event only)\n");
+      break;
+    case  K_MOUSE_URL    :
+      printf("\\Kmouseurl      Mouse: Start browser with selected URL\n");
+      break;
+#endif /* OS2MOUSE */
+
+/* ANSI Function Key definitions */
+    case  K_ANSIF01          :
+      printf("\\Kansif01       Transmit SCOANSI/AT386: F1 \n");
+      break;
+    case  K_ANSIF02          :
+      printf("\\Kansif02       Transmit SCOANSI/AT386: F2 \n");
+      break;
+    case  K_ANSIF03          :
+      printf("\\Kansif03       Transmit SCOANSI/AT386: F3 \n");
+      break;
+    case  K_ANSIF04          :
+      printf("\\Kansif04       Transmit SCOANSI/AT386: F4 \n");
+      break;
+    case  K_ANSIF05          :
+      printf("\\Kansif05       Transmit SCOANSI/AT386: F5 \n");
+      break;
+    case  K_ANSIF06          :
+      printf("\\Kansif06       Transmit SCOANSI/AT386: F6 \n");
+      break;
+    case  K_ANSIF07          :
+      printf("\\Kansif07       Transmit SCOANSI/AT386: F7 \n");
+      break;
+    case  K_ANSIF08          :
+      printf("\\Kansif08       Transmit SCOANSI/AT386: F8 \n");
+      break;
+    case  K_ANSIF09          :
+      printf("\\Kansif09       Transmit SCOANSI/AT386: F9 \n");
+      break;
+    case  K_ANSIF10          :
+      printf("\\Kansif10       Transmit SCOANSI/AT386: F10\n");
+      break;
+    case  K_ANSIF11          :
+      printf("\\Kansif11       Transmit SCOANSI/AT386: F11\n");
+      break;
+    case  K_ANSIF12          :
+      printf("\\Kansif12       Transmit SCOANSI/AT386: F12\n");
+      break;
+    case  K_ANSIF13          :
+      printf("\\Kansif13       Transmit SCOANSI/AT386: Shift-F1 \n");
+      break;
+    case  K_ANSIF14          :
+      printf("\\Kansif14       Transmit SCOANSI/AT386: Shift-F2 \n");
+      break;
+    case  K_ANSIF15          :
+      printf("\\Kansif15       Transmit SCOANSI/AT386: Shift-F3 \n");
+      break;
+    case  K_ANSIF16          :
+      printf("\\Kansif16       Transmit SCOANSI/AT386: Shift-F4 \n");
+      break;
+    case  K_ANSIF17          :
+      printf("\\Kansif17       Transmit SCOANSI/AT386: Shift-F5 \n");
+      break;
+    case  K_ANSIF18          :
+      printf("\\Kansif18       Transmit SCOANSI/AT386: Shift-F6 \n");
+      break;
+    case  K_ANSIF19          :
+      printf("\\Kansif19       Transmit SCOANSI/AT386: Shift-F7 \n");
+      break;
+    case  K_ANSIF20          :
+      printf("\\Kansif20       Transmit SCOANSI/AT386: Shift-F8 \n");
+      break;
+    case  K_ANSIF21          :
+      printf("\\Kansif21       Transmit SCOANSI/AT386: Shift-F9 \n");
+      break;
+    case  K_ANSIF22          :
+      printf("\\Kansif22       Transmit SCOANSI/AT386: Shift-F10\n");
+      break;
+    case  K_ANSIF23          :
+      printf("\\Kansif23       Transmit SCOANSI/AT386: Shift-F11\n");
+      break;
+    case  K_ANSIF24          :
+      printf("\\Kansif24       Transmit SCOANSI/AT386: Shift-F12\n");
+      break;
+    case  K_ANSIF25          :
+      printf("\\Kansif25       Transmit SCOANSI/AT386: Ctrl-F1 \n");
+      break;
+    case  K_ANSIF26          :
+      printf("\\Kansif26       Transmit SCOANSI/AT386: Ctrl-F2 \n");
+      break;
+    case  K_ANSIF27          :
+      printf("\\Kansif27       Transmit SCOANSI/AT386: Ctrl-F3 \n");
+      break;
+    case  K_ANSIF28          :
+      printf("\\Kansif28       Transmit SCOANSI/AT386: Ctrl-F4 \n");
+      break;
+    case  K_ANSIF29          :
+      printf("\\Kansif29       Transmit SCOANSI/AT386: Ctrl-F5 \n");
+      break;
+    case  K_ANSIF30          :
+      printf("\\Kansif30       Transmit SCOANSI/AT386: Ctrl-F6 \n");
+      break;
+    case  K_ANSIF31          :
+      printf("\\Kansif31       Transmit SCOANSI/AT386: Ctrl-F7 \n");
+      break;
+    case  K_ANSIF32          :
+      printf("\\Kansif32       Transmit SCOANSI/AT386: Ctrl-F8 \n");
+      break;
+    case  K_ANSIF33          :
+      printf("\\Kansif33       Transmit SCOANSI/AT386: Ctrl-F9 \n");
+      break;
+    case  K_ANSIF34          :
+      printf("\\Kansif34       Transmit SCOANSI/AT386: Ctrl-F10\n");
+      break;
+    case  K_ANSIF35          :
+      printf("\\Kansif35       Transmit SCOANSI/AT386: Ctrl-F11\n");
+      break;
+    case  K_ANSIF36          :
+      printf("\\Kansif36       Transmit SCOANSI/AT386: Ctrl-F12\n");
+      break;
+    case  K_ANSIF37          :
+      printf("\\Kansif37       Transmit SCOANSI/AT386: Ctrl-Shift-F1 \n");
+      break;
+    case  K_ANSIF38          :
+      printf("\\Kansif38       Transmit SCOANSI/AT386: Ctrl-Shift-F2 \n");
+      break;
+    case  K_ANSIF39          :
+      printf("\\Kansif39       Transmit SCOANSI/AT386: Ctrl-Shift-F3 \n");
+      break;
+    case  K_ANSIF40          :
+      printf("\\Kansif40       Transmit SCOANSI/AT386: Ctrl-Shift-F4 \n");
+      break;
+    case  K_ANSIF41          :
+      printf("\\Kansif41       Transmit SCOANSI/AT386: Ctrl-Shift-F5 \n");
+      break;
+    case  K_ANSIF42          :
+      printf("\\Kansif42       Transmit SCOANSI/AT386: Ctrl-Shift-F6 \n");
+      break;
+    case  K_ANSIF43          :
+      printf("\\Kansif43       Transmit SCOANSI/AT386: Ctrl-Shift-F7 \n");
+      break;
+    case  K_ANSIF44          :
+      printf("\\Kansif44       Transmit SCOANSI/AT386: Ctrl-Shift-F8 \n");
+      break;
+    case  K_ANSIF45          :
+      printf("\\Kansif45       Transmit SCOANSI/AT386: Ctrl-Shift-F9 \n");
+      break;
+    case  K_ANSIF46          :
+      printf("\\Kansif46       Transmit SCOANSI/AT386: Ctrl-Shift-F10\n");
+      break;
+    case  K_ANSIF47          :
+      printf("\\Kansif47       Transmit SCOANSI/AT386: Ctrl-Shift-F11\n");
+      break;
+    case  K_ANSIF48          :
+      printf("\\Kansif48       Transmit SCOANSI/AT386: Ctrl-Shift-F12\n");
+      break;
+    case  K_ANSIF49          :
+      printf("\\Kansif49       Transmit SCOANSI/AT386: Home\n");
+      break;
+    case  K_ANSIF50          :
+      printf("\\Kansif50       Transmit SCOANSI/AT386: Up Arrow\n");
+      break;
+    case  K_ANSIF51          :
+      printf("\\Kansif51       Transmit SCOANSI/AT386: PgUp\n");
+      break;
+    case  K_ANSIF52          :
+      printf("\\Kansif52       Transmit SCOANSI/AT386: Ctrl-Shift-Subtract\n");
+      break;
+    case  K_ANSIF53          :
+      printf("\\Kansif53       Transmit SCOANSI/AT386: Left Arrow\n");
+      break;
+    case  K_ANSIF54          :
+      printf("\\Kansif54       Transmit SCOANSI/AT386: Clear\n");
+      break;
+    case  K_ANSIF55          :
+      printf("\\Kansif55       Transmit SCOANSI/AT386: Right Arrow\n");
+      break;
+    case  K_ANSIF56          :
+      printf("\\Kansif56       Transmit SCOANSI/AT386: Shift-Add\n");
+      break;
+    case  K_ANSIF57          :
+      printf("\\Kansif57       Transmit SCOANSI/AT386: End\n");
+      break;
+    case  K_ANSIF58          :
+      printf("\\Kansif58       Transmit SCOANSI/AT386: Down Arrow\n");
+      break;
+    case  K_ANSIF59          :
+      printf("\\Kansif59       Transmit SCOANSI/AT386: PgDn\n");
+      break;
+    case  K_ANSIF60          :
+      printf("\\Kansif60       Transmit SCOANSI/AT386: Insert\n");
+      break;
+    case  K_ANSIF61          :
+      printf("\\Kansif61       Transmit SCOANSI/AT386: (not named)\n");
+      break;
+
+/* WYSE Function Keys (unshifted) */
+    case  K_WYF01            :
+      printf("\\Kwyf01         Transmit WYSE 30/50/60/160: F1\n");
+      break;
+    case  K_WYF02            :
+      printf("\\Kwyf02         Transmit WYSE 30/50/60/160: F2\n");
+      break;
+    case  K_WYF03            :
+      printf("\\Kwyf03         Transmit WYSE 30/50/60/160: F3\n");
+      break;
+    case  K_WYF04            :
+      printf("\\Kwyf04         Transmit WYSE 30/50/60/160: F4\n");
+      break;
+    case  K_WYF05            :
+      printf("\\Kwyf05         Transmit WYSE 30/50/60/160: F5\n");
+      break;
+    case  K_WYF06            :
+      printf("\\Kwyf06         Transmit WYSE 30/50/60/160: F6\n");
+      break;
+    case  K_WYF07            :
+      printf("\\Kwyf07         Transmit WYSE 30/50/60/160: F7\n");
+      break;
+    case  K_WYF08            :
+      printf("\\Kwyf08         Transmit WYSE 30/50/60/160: F8\n");
+      break;
+    case  K_WYF09            :
+      printf("\\Kwyf09         Transmit WYSE 30/50/60/160: F9\n");
+      break;
+    case  K_WYF10            :
+      printf("\\Kwyf10         Transmit WYSE 30/50/60/160: F10\n");
+      break;
+    case  K_WYF11            :
+      printf("\\Kwyf11         Transmit WYSE 30/50/60/160: F11\n");
+      break;
+    case  K_WYF12            :
+      printf("\\Kwyf12         Transmit WYSE 30/50/60/160: F12\n");
+      break;
+    case  K_WYF13            :
+      printf("\\Kwyf13         Transmit WYSE 30/50/60/160: F13\n");
+      break;
+    case  K_WYF14            :
+      printf("\\Kwyf14         Transmit WYSE 30/50/60/160: F14\n");
+      break;
+    case  K_WYF15            :
+      printf("\\Kwyf15         Transmit WYSE 30/50/60/160: F15\n");
+      break;
+    case  K_WYF16            :
+      printf("\\Kwyf16         Transmit WYSE 30/50/60/160: F16\n");
+      break;
+    case  K_WYF17            :
+      printf("\\Kwyf17         Transmit WYSE 30/50/60/160: F17\n");
+      break;
+    case  K_WYF18            :
+      printf("\\Kwyf18         Transmit WYSE 30/50/60/160: F18\n");
+      break;
+    case  K_WYF19            :
+      printf("\\Kwyf19         Transmit WYSE 30/50/60/160: F19\n");
+      break;
+    case  K_WYF20            :
+      printf("\\Kwyf20         Transmit WYSE 30/50/60/160: F20\n");
+      break;
+
+/* WYSE Function Keys (shifted) */
+    case  K_WYSF01           :
+      printf("\\Kwysf01        Transmit WYSE 30/50/60/160: Shift-F1\n");
+      break;
+    case  K_WYSF02           :
+      printf("\\Kwysf02        Transmit WYSE 30/50/60/160: Shift-F2\n");
+      break;
+    case  K_WYSF03            :
+      printf("\\Kwysf03        Transmit WYSE 30/50/60/160: Shift-F3\n");
+      break;
+    case  K_WYSF04            :
+      printf("\\Kwysf04        Transmit WYSE 30/50/60/160: Shift-F4\n");
+      break;
+    case  K_WYSF05            :
+      printf("\\Kwysf05        Transmit WYSE 30/50/60/160: Shift-F5\n");
+      break;
+    case  K_WYSF06            :
+      printf("\\Kwysf06        Transmit WYSE 30/50/60/160: Shift-F6\n");
+      break;
+    case  K_WYSF07            :
+      printf("\\Kwysf07        Transmit WYSE 30/50/60/160: Shift-F7\n");
+      break;
+    case  K_WYSF08            :
+      printf("\\Kwysf08        Transmit WYSE 30/50/60/160: Shift-F8\n");
+      break;
+    case  K_WYSF09            :
+      printf("\\Kwysf09        Transmit WYSE 30/50/60/160: Shift-F9\n");
+      break;
+    case  K_WYSF10            :
+      printf("\\Kwysf10        Transmit WYSE 30/50/60/160: Shift-F10\n");
+      break;
+    case  K_WYSF11            :
+      printf("\\Kwysf11        Transmit WYSE 30/50/60/160: Shift-F11\n");
+      break;
+    case  K_WYSF12            :
+      printf("\\Kwysf12        Transmit WYSE 30/50/60/160: Shift-F12\n");
+      break;
+    case  K_WYSF13            :
+      printf("\\Kwysf13        Transmit WYSE 30/50/60/160: Shift-F13\n");
+      break;
+    case  K_WYSF14            :
+      printf("\\Kwysf14        Transmit WYSE 30/50/60/160: Shift-F14\n");
+      break;
+    case  K_WYSF15            :
+      printf("\\Kwysf15        Transmit WYSE 30/50/60/160: Shift-F15\n");
+      break;
+    case  K_WYSF16            :
+      printf("\\Kwysf16        Transmit WYSE 30/50/60/160: Shift-F16\n");
+      break;
+    case  K_WYSF17           :
+      printf("\\Kwysf17        Transmit WYSE 30/50/60/160: Shift-F17\n");
+      break;
+    case  K_WYSF18           :
+      printf("\\Kwysf18        Transmit WYSE 30/50/60/160: Shift-F18\n");
+      break;
+    case  K_WYSF19           :
+      printf("\\Kwysf19        Transmit WYSE 30/50/60/160: Shift-F19\n");
+      break;
+    case  K_WYSF20           :
+      printf("\\Kwysf20        Transmit WYSE 30/50/60/160: Shift-F20\n");
+      break;
+
+/* WYSE Edit and Special Keys */
+    case  K_WYBS         :
+      printf("\\Kwybs          Transmit WYSE 30/50/60/160: Backspace\n");
+      break;
+    case  K_WYCLRLN          :
+      printf("\\Kwyclrln       Transmit WYSE 30/50/60/160: Clear Line\n");
+      break;
+    case  K_WYSCLRLN     :
+     printf("\\Kwysclrln      Transmit WYSE 30/50/60/160: Shift-Clear Line\n");
+      break;
+    case  K_WYCLRPG      :
+      printf("\\Kwyclrpg       Transmit WYSE 30/50/60/160: Clear Page\n");
+      break;
+    case  K_WYSCLRPG     :
+    printf("\\Kwysclrpg      Transmit WYSE 30/50/60/160: Shift-Clear Page\n");
+      break;
+    case  K_WYDELCHAR    :
+      printf("\\Kwydelchar     Transmit WYSE 30/50/60/160: Delete Char\n");
+      break;
+    case  K_WYDELLN      :
+      printf("\\Kwydelln       Transmit WYSE 30/50/60/160: Delete Line\n");
+      break;
+    case  K_WYENTER          :
+      printf("\\Kwyenter       Transmit WYSE 30/50/60/160: Enter\n");
+      break;
+    case  K_WYESC            :
+      printf("\\Kwyesc         Transmit WYSE 30/50/60/160: Esc\n");
+      break;
+    case  K_WYHOME           :
+      printf("\\Kwyhome        Transmit WYSE 30/50/60/160: Home\n");
+      break;
+    case  K_WYSHOME          :
+      printf("\\Kwyshome       Transmit WYSE 30/50/60/160: Shift-Home\n");
+      break;
+    case  K_WYINSERT     :
+      printf("\\Kwyinsert      Transmit WYSE 30/50/60/160: Insert\n");
+      break;
+    case  K_WYINSCHAR    :
+      printf("\\Kwyinschar     Transmit WYSE 30/50/60/160: Insert Char\n");
+      break;
+    case  K_WYINSLN          :
+      printf("\\Kwyinsln       Transmit WYSE 30/50/60/160: Insert Line\n");
+      break;
+    case  K_WYPGNEXT     :
+      printf("\\Kwypgnext      Transmit WYSE 30/50/60/160: Page Next\n");
+      break;
+    case  K_WYPGPREV     :
+      printf("\\Kwypgprev      Transmit WYSE 30/50/60/160: Page Previous\n");
+      break;
+    case  K_WYREPLACE    :
+      printf("\\Kwyreplace     Transmit WYSE 30/50/60/160: Replace      \n");
+      break;
+    case  K_WYRETURN     :
+      printf("\\Kwyreturn      Transmit WYSE 30/50/60/160: Return       \n");
+      break;
+    case  K_WYTAB            :
+      printf("\\Kwytab         Transmit WYSE 30/50/60/160: Tab          \n");
+      break;
+    case  K_WYSTAB           :
+      printf("\\Kwystab        Transmit WYSE 30/50/60/160: Shift-Tab    \n");
+      break;
+    case  K_WYPRTSCN     :
+      printf("\\Kwyprtscn      Transmit WYSE 30/50/60/160: Print Screen \n");
+      break;
+    case  K_WYSESC       :
+      printf("\\Kwysesc        Transmit WYSE 30/50/60/160: Shift-Esc    \n");
+      break;
+    case  K_WYSBS        :
+    printf("\\Kwysbs         Transmit WYSE 30/50/60/160: Shift-Backspace\n");
+      break;
+    case  K_WYSENTER     :
+      printf("\\Kwysenter      Transmit WYSE 30/50/60/160: Shift-Enter\n");
+      break;
+    case  K_WYSRETURN    :
+      printf("\\Kwysreturn     Transmit WYSE 30/50/60/160: Shift-Return\n");
+      break;
+    case  K_WYUPARR          :
+      printf("\\Kwyuparr       Transmit WYSE 30/50/60/160: Up Arrow\n");
+      break;
+    case  K_WYDNARR          :
+      printf("\\Kwydnarr       Transmit WYSE 30/50/60/160: Down Arrow\n");
+      break;
+    case  K_WYLFARR          :
+      printf("\\Kwylfarr       Transmit WYSE 30/50/60/160: Left Arrow\n");
+      break;
+    case  K_WYRTARR          :
+      printf("\\Kwyrtarr       Transmit WYSE 30/50/60/160: Right Arrow\n");
+      break;
+    case  K_WYSUPARR     :
+      printf("\\Kwysuparr      Transmit WYSE 30/50/60/160: Shift-Up Arrow\n");
+      break;
+    case  K_WYSDNARR     :
+    printf("\\Kwysdnarr      Transmit WYSE 30/50/60/160: Shift-Down Arrow\n");
+      break;
+    case  K_WYSLFARR     :
+    printf("\\Kwyslfarr      Transmit WYSE 30/50/60/160: Shift-Left Arrow\n");
+      break;
+    case  K_WYSRTARR     :
+    printf("\\Kwysrtarr      Transmit WYSE 30/50/60/160: Shift-Right Arrow\n");
+      break;
+    case  K_WYSEND:
+      printf("\\Kwysend        Transmit WYSE 30/50/60/160: Send\n");
+      break;
+    case  K_WYSSEND:
+      printf("\\Kwyssend       Transmit WYSE 30/50/60/160: Shift-Send\n");
+      break;
+
+/* Data General Function Keys (unshifted) */
+    case  K_DGF01            :
+      printf("\\Kdgf01         Transmit Data General: F1                 \n");
+      break;
+    case  K_DGF02            :
+      printf("\\Kdgf01         Transmit Data General: F2                 \n");
+      break;
+    case  K_DGF03            :
+      printf("\\Kdgf01         Transmit Data General: F3                 \n");
+      break;
+    case  K_DGF04            :
+      printf("\\Kdgf01         Transmit Data General: F4                 \n");
+      break;
+    case  K_DGF05            :
+      printf("\\Kdgf01         Transmit Data General: F5                 \n");
+      break;
+    case  K_DGF06            :
+      printf("\\Kdgf01         Transmit Data General: F6                 \n");
+      break;
+    case  K_DGF07            :
+      printf("\\Kdgf01         Transmit Data General: F7                 \n");
+      break;
+    case  K_DGF08            :
+      printf("\\Kdgf01         Transmit Data General: F8                 \n");
+      break;
+    case  K_DGF09            :
+      printf("\\Kdgf01         Transmit Data General: F9                 \n");
+      break;
+    case  K_DGF10            :
+      printf("\\Kdgf01         Transmit Data General: F10                \n");
+      break;
+    case  K_DGF11            :
+      printf("\\Kdgf01         Transmit Data General: F11                \n");
+      break;
+    case  K_DGF12            :
+      printf("\\Kdgf01         Transmit Data General: F12                \n");
+      break;
+    case  K_DGF13            :
+      printf("\\Kdgf01         Transmit Data General: F13                \n");
+      break;
+    case  K_DGF14            :
+      printf("\\Kdgf01         Transmit Data General: F14                \n");
+      break;
+    case  K_DGF15            :
+      printf("\\Kdgf01         Transmit Data General: F15                \n");
+      break;
+
+/* Data General Function Keys (shifted) */
+    case  K_DGSF01           :
+      printf(
+      "\\Kdgsf01        Transmit Data General: Shift-F1                 \n");
+      break;
+    case  K_DGSF02           :
+      printf(
+      "\\Kdgsf02        Transmit Data General: Shift-F2                 \n");
+      break;
+    case  K_DGSF03           :
+      printf(
+      "\\Kdgsf03        Transmit Data General: Shift-F3                 \n");
+      break;
+    case  K_DGSF04           :
+      printf(
+      "\\Kdgsf04        Transmit Data General: Shift-F4                 \n");
+      break;
+    case  K_DGSF05           :
+      printf(
+      "\\Kdgsf05        Transmit Data General: Shift-F5                 \n");
+      break;
+    case  K_DGSF06           :
+      printf(
+      "\\Kdgsf06        Transmit Data General: Shift-F6                 \n");
+      break;
+    case  K_DGSF07           :
+      printf(
+      "\\Kdgsf07        Transmit Data General: Shift-F7                 \n");
+      break;
+    case  K_DGSF08           :
+      printf(
+      "\\Kdgsf08        Transmit Data General: Shift-F8                 \n");
+      break;
+    case  K_DGSF09           :
+      printf(
+      "\\Kdgsf09        Transmit Data General: Shift-F9                 \n");
+      break;
+    case  K_DGSF10           :
+      printf(
+      "\\Kdgsf10        Transmit Data General: Shift-F10                \n");
+      break;
+    case  K_DGSF11           :
+      printf(
+      "\\Kdgsf11        Transmit Data General: Shift-F11                \n");
+      break;
+    case  K_DGSF12           :
+      printf(
+      "\\Kdgsf12        Transmit Data General: Shift-F12                \n");
+      break;
+    case  K_DGSF13           :
+      printf(
+      "\\Kdgsf13        Transmit Data General: Shift-F13                \n");
+      break;
+    case  K_DGSF14           :
+      printf(
+      "\\Kdgsf14        Transmit Data General: Shift-F14                \n");
+      break;
+    case  K_DGSF15           :
+      printf(
+      "\\Kdgsf15        Transmit Data General: Shift-F15                \n");
+      break;
+
+/* Data General Function Keys (control) */
+    case  K_DGCF01           :
+      printf(
+      "\\Kdgcf01        Transmit Data General: Ctrl-F1                 \n");
+      break;
+    case  K_DGCF02            :
+      printf(
+      "\\Kdgcf02        Transmit Data General: Ctrl-F2                 \n");
+      break;
+    case  K_DGCF03            :
+      printf(
+      "\\Kdgcf03        Transmit Data General: Ctrl-F3                 \n");
+      break;
+    case  K_DGCF04            :
+      printf(
+      "\\Kdgcf04        Transmit Data General: Ctrl-F4                 \n");
+      break;
+    case  K_DGCF05            :
+      printf(
+      "\\Kdgcf05        Transmit Data General: Ctrl-F5                 \n");
+      break;
+    case  K_DGCF06            :
+      printf(
+      "\\Kdgcf06        Transmit Data General: Ctrl-F6                 \n");
+      break;
+    case  K_DGCF07            :
+      printf(
+      "\\Kdgcf07        Transmit Data General: Ctrl-F7                 \n");
+      break;
+    case  K_DGCF08            :
+      printf(
+      "\\Kdgcf08        Transmit Data General: Ctrl-F8                 \n");
+      break;
+    case  K_DGCF09            :
+      printf(
+      "\\Kdgcf09        Transmit Data General: Ctrl-F9                 \n");
+      break;
+    case  K_DGCF10            :
+      printf(
+      "\\Kdgcf10        Transmit Data General: Ctrl-F10                \n");
+      break;
+    case  K_DGCF11            :
+      printf(
+      "\\Kdgcf11        Transmit Data General: Ctrl-F11                \n");
+      break;
+    case  K_DGCF12            :
+      printf(
+      "\\Kdgcf12        Transmit Data General: Ctrl-F12                \n");
+      break;
+    case  K_DGCF13            :
+      printf(
+      "\\Kdgcf13        Transmit Data General: Ctrl-F13                \n");
+      break;
+    case  K_DGCF14            :
+      printf(
+      "\\Kdgcf14        Transmit Data General: Ctrl-F14                \n");
+      break;
+    case  K_DGCF15            :
+      printf(
+      "\\Kdgcf15        Transmit Data General: Ctrl-F15                \n");
+      break;
+
+/* Data General Function Keys (control shifted) */
+    case  K_DGCSF01          :
+      printf(
+    "\\Kdgcsf01       Transmit Data General: Ctrl-Shift-F1                \n");
+      break;
+    case  K_DGCSF02          :
+      printf(
+    "\\Kdgcsf02       Transmit Data General: Ctrl-Shift-F2                \n");
+      break;
+    case  K_DGCSF03          :
+      printf(
+    "\\Kdgcsf03       Transmit Data General: Ctrl-Shift-F3                \n");
+      break;
+    case  K_DGCSF04          :
+      printf(
+    "\\Kdgcsf04       Transmit Data General: Ctrl-Shift-F4                \n");
+      break;
+    case  K_DGCSF05          :
+      printf(
+    "\\Kdgcsf05       Transmit Data General: Ctrl-Shift-F5                \n");
+      break;
+    case  K_DGCSF06          :
+      printf(
+    "\\Kdgcsf06       Transmit Data General: Ctrl-Shift-F6                \n");
+      break;
+    case  K_DGCSF07          :
+      printf(
+    "\\Kdgcsf07       Transmit Data General: Ctrl-Shift-F7                \n");
+      break;
+    case  K_DGCSF08          :
+      printf(
+    "\\Kdgcsf08       Transmit Data General: Ctrl-Shift-F8                \n");
+      break;
+    case  K_DGCSF09          :
+      printf(
+    "\\Kdgcsf09       Transmit Data General: Ctrl-Shift-F9                \n");
+      break;
+    case  K_DGCSF10          :
+      printf(
+    "\\Kdgcsf10       Transmit Data General: Ctrl-Shift-F10               \n");
+      break;
+    case  K_DGCSF11          :
+      printf(
+    "\\Kdgcsf11       Transmit Data General: Ctrl-Shift-F11               \n");
+      break;
+    case  K_DGCSF12          :
+      printf(
+    "\\Kdgcsf12       Transmit Data General: Ctrl-Shift-F12               \n");
+      break;
+    case  K_DGCSF13          :
+      printf(
+    "\\Kdgcsf13       Transmit Data General: Ctrl-Shift-F13               \n");
+      break;
+    case  K_DGCSF14          :
+      printf(
+    "\\Kdgcsf14       Transmit Data General: Ctrl-Shift-F14               \n");
+      break;
+    case  K_DGCSF15          :
+      printf(
+    "\\Kdgcsf15       Transmit Data General: Ctrl-Shift-F15               \n");
+      break;
+
+    case  K_DGUPARR          :
+      printf("\\Kdguparr       Transmit Data General: Up Arrow          \n");
+      break;
+    case  K_DGDNARR          :
+      printf("\\Kdgdnarr       Transmit Data General: Down Arrow        \n");
+      break;
+    case  K_DGLFARR          :
+      printf("\\Kdglfarr       Transmit Data General: Left Arrow        \n");
+      break;
+    case  K_DGRTARR          :
+      printf("\\Kdgrtarr       Transmit Data General: Right Arrow       \n");
+      break;
+    case  K_DGSUPARR     :
+      printf("\\Kdgsuparr      Transmit Data General: Shift-Up Arrow    \n");
+      break;
+    case  K_DGSDNARR     :
+      printf("\\Kdgsdnarr      Transmit Data General: Shift-Down Arrow  \n");
+      break;
+    case  K_DGSLFARR     :
+      printf("\\Kdgslfarr      Transmit Data General: Shift-Left Arrow  \n");
+      break;
+    case  K_DGSRTARR     :
+      printf("\\Kdgsrtarr      Transmit Data General: Shift-Right Arrow \n");
+      break;
+
+    case  K_DGERASEPAGE  :
+      printf("\\Kdgerasepage   Transmit Data General: Erase Page        \n");
+      break;
+    case  K_DGC1             :
+      printf("\\Kdgc1          Transmit Data General: C1                \n");
+      break;
+    case  K_DGC2             :
+      printf("\\Kdgc2          Transmit Data General: C2                \n");
+      break;
+    case  K_DGERASEEOL   :
+      printf("\\Kdgeraseeol    Transmit Data General: Erase EOL         \n");
+      break;
+    case  K_DGC3             :
+      printf("\\Kdgc3          Transmit Data General: C3                \n");
+      break;
+    case  K_DGC4             :
+      printf("\\Kdgc4          Transmit Data General: C4                \n");
+      break;
+    case  K_DGCMDPRINT   :
+      printf("\\Kdgcmdprint    Transmit Data General: Command Print     \n");
+      break;
+    case  K_DGHOME       :
+      printf("\\Kdghome        Transmit Data General: Home              \n");
+      break;
+    case  K_DGSERASEPAGE :
+      printf("\\Kdgserasepage  Transmit Data General: Erase Page        \n");
+      break;
+    case  K_DGSC1            :
+      printf("\\Kdgsc1         Transmit Data General: Shift-C1          \n");
+      break;
+    case  K_DGSC2            :
+      printf("\\Kdgsc2         Transmit Data General: Shift-C2          \n");
+      break;
+    case  K_DGSERASEEOL  :
+      printf("\\Kdgseraseeol   Transmit Data General: Shift-Erase EOL  \n");
+      break;
+    case  K_DGSC3            :
+      printf("\\Kdgsc3         Transmit Data General: Shift-C3          \n");
+      break;
+    case  K_DGSC4            :
+      printf("\\Kdgsc4         Transmit Data General: Shift-C4          \n");
+      break;
+    case  K_DGSCMDPRINT  :
+      printf("\\Kdgscmdprint   Transmit Data General: Shift-Command Print\n");
+      break;
+    case  K_DGBS         :
+      printf("\\Kdgbs          Transmit Data General: Backspace         \n");
+      break;
+    case  K_DGSHOME      :
+      printf("\\Kdshome        Transmit Data General: Shift-Home        \n");
+      break;
+
+
+/* Televideo Function Keys (unshifted) */
+    case  K_TVIF01           :
+      printf("\\Ktvif01        Transmit Televideo: F1       \n");
+      break;
+    case  K_TVIF02           :
+      printf("\\Ktvif02        Transmit Televideo: F2              \n");
+      break;
+    case  K_TVIF03           :
+      printf("\\Ktvif03        Transmit Televideo: F3             \n");
+      break;
+    case  K_TVIF04           :
+      printf("\\Ktvif04        Transmit Televideo: F4              \n");
+      break;
+    case  K_TVIF05           :
+      printf("\\Ktvif05        Transmit Televideo: F5              \n");
+      break;
+    case  K_TVIF06           :
+      printf("\\Ktvif06        Transmit Televideo: F6              \n");
+      break;
+    case  K_TVIF07           :
+      printf("\\Ktvif07        Transmit Televideo: F7              \n");
+      break;
+    case  K_TVIF08           :
+      printf("\\Ktvif08        Transmit Televideo: F8              \n");
+      break;
+    case  K_TVIF09           :
+      printf("\\Ktvif09        Transmit Televideo: F9              \n");
+      break;
+    case  K_TVIF10           :
+      printf("\\Ktvif10        Transmit Televideo: F10             \n");
+      break;
+    case  K_TVIF11           :
+      printf("\\Ktvif11        Transmit Televideo: F11             \n");
+      break;
+    case  K_TVIF12           :
+      printf("\\Ktvif12        Transmit Televideo: F12             \n");
+      break;
+    case  K_TVIF13           :
+      printf("\\Ktvif13        Transmit Televideo: F13             \n");
+      break;
+    case  K_TVIF14           :
+      printf("\\Ktvif14        Transmit Televideo: F14             \n");
+      break;
+    case  K_TVIF15           :
+      printf("\\Ktvif15        Transmit Televideo: F15             \n");
+      break;
+    case  K_TVIF16           :
+      printf("\\Ktvif16        Transmit Televideo: F16             \n");
+      break;
+
+/* Televideo Function Keys (shifted) */
+    case  K_TVISF01          :
+      printf("\\Ktvisf01       Transmit Televideo: Shift-F1 \n");
+      break;
+    case  K_TVISF02          :
+      printf("\\Ktvisf02       Transmit Televideo: Shift-F2 \n");
+      break;
+    case  K_TVISF03            :
+      printf("\\Ktvisf03       Transmit Televideo: Shift-F3 \n");
+      break;
+    case  K_TVISF04            :
+      printf("\\Ktvisf04       Transmit Televideo: Shift-F4 \n");
+      break;
+    case  K_TVISF05            :
+      printf("\\Ktvisf05       Transmit Televideo: Shift-F5 \n");
+      break;
+    case  K_TVISF06            :
+      printf("\\Ktvisf06       Transmit Televideo: Shift-F6 \n");
+      break;
+    case  K_TVISF07            :
+      printf("\\Ktvisf07       Transmit Televideo: Shift-F7 \n");
+      break;
+    case  K_TVISF08            :
+      printf("\\Ktvisf08       Transmit Televideo: Shift-F8 \n");
+      break;
+    case  K_TVISF09            :
+      printf("\\Ktvisf09       Transmit Televideo: Shift-F9 \n");
+      break;
+    case  K_TVISF10            :
+      printf("\\Ktvisf10       Transmit Televideo: Shift-F10\n");
+      break;
+    case  K_TVISF11            :
+      printf("\\Ktvisf11       Transmit Televideo: Shift-F11\n");
+      break;
+    case  K_TVISF12            :
+      printf("\\Ktvisf12       Transmit Televideo: Shift-F12\n");
+      break;
+    case  K_TVISF13            :
+      printf("\\Ktvisf13       Transmit Televideo: Shift-F13\n");
+      break;
+    case  K_TVISF14            :
+      printf("\\Ktvisf14       Transmit Televideo: Shift-F14\n");
+      break;
+    case  K_TVISF15            :
+      printf("\\Ktvisf15       Transmit Televideo: Shift-F15\n");
+      break;
+    case  K_TVISF16            :
+      printf("\\Ktvisf16       Transmit Televideo: Shift-F16\n");
+      break;
+
+/* Televideo Edit and Special Keys */
+    case  K_TVIBS         :
+      printf("\\Ktvibs         Transmit Televideo: Backspace       \n");
+      break;
+    case  K_TVICLRLN         :
+      printf("\\Ktviclrln      Transmit Televideo: Clear Line      \n");
+      break;
+    case  K_TVISCLRLN     :
+      printf("\\Ktvisclrln     Transmit Televideo: Shift-Clear Line\n");
+      break;
+    case  K_TVICLRPG      :
+      printf("\\Ktviclrpg      Transmit Televideo: Clear Page      \n");
+      break;
+    case  K_TVISCLRPG     :
+      printf("\\Ktvisclrpg     Transmit Televideo: Shift-Clear Page\n");
+      break;
+    case  K_TVIDELCHAR    :
+      printf("\\Ktvidelchar    Transmit Televideo: Delete Char     \n");
+      break;
+    case  K_TVIDELLN      :
+      printf("\\Ktvidelln      Transmit Televideo: Delete Line     \n");
+      break;
+    case  K_TVIENTER         :
+      printf("\\Ktvienter      Transmit Televideo: Enter           \n");
+      break;
+    case  K_TVIESC           :
+      printf("\\Ktviesc        Transmit Televideo: Esc             \n");
+      break;
+    case  K_TVIHOME          :
+      printf("\\Ktvihome       Transmit Televideo: Home            \n");
+      break;
+    case  K_TVISHOME         :
+      printf("\\Ktvishome      Transmit Televideo: Shift-Home      \n");
+      break;
+    case  K_TVIINSERT     :
+      printf("\\Ktviinsert     Transmit Televideo: Insert          \n");
+      break;
+    case  K_TVIINSCHAR    :
+      printf("\\Ktviinschar    Transmit Televideo: Insert Char     \n");
+      break;
+    case  K_TVIINSLN         :
+      printf("\\Ktviinsln      Transmit Televideo: Insert Line     \n");
+      break;
+    case  K_TVIPGNEXT     :
+      printf("\\Ktvipgnext     Transmit Televideo: Page Next       \n");
+      break;
+    case  K_TVIPGPREV     :
+      printf("\\Ktvipgprev     Transmit Televideo: Page Previous   \n");
+      break;
+    case  K_TVIREPLACE    :
+      printf("\\Ktvireplace    Transmit Televideo: Replace         \n");
+      break;
+    case  K_TVIRETURN     :
+      printf("\\Ktvireturn     Transmit Televideo: Return          \n");
+      break;
+    case  K_TVITAB           :
+      printf("\\Ktvitab        Transmit Televideo: Tab             \n");
+      break;
+    case  K_TVISTAB          :
+      printf("\\Ktvistab       Transmit Televideo: Shift-Tab       \n");
+      break;
+    case  K_TVIPRTSCN     :
+      printf("\\Ktviprtscn     Transmit Televideo: Print Screen    \n");
+      break;
+    case  K_TVISESC       :
+      printf("\\Ktvisesc       Transmit Televideo: Shift-Esc       \n");
+      break;
+    case  K_TVISBS        :
+      printf("\\Ktvisbs        Transmit Televideo: Shift-Backspace \n");
+      break;
+    case  K_TVISENTER     :
+      printf("\\Ktvisenter     Transmit Televideo: Shift-Enter     \n");
+      break;
+    case  K_TVISRETURN    :
+      printf("\\Ktvisreturn    Transmit Televideo: Shift-Return    \n");
+      break;
+    case  K_TVIUPARR         :
+      printf("\\Ktviuparr      Transmit Televideo: Up Arrow        \n");
+      break;
+    case  K_TVIDNARR         :
+      printf("\\Ktvidnarr      Transmit Televideo: Down Arrow      \n");
+      break;
+    case  K_TVILFARR         :
+      printf("\\Ktvilfarr      Transmit Televideo: Left Arrow      \n");
+      break;
+    case  K_TVIRTARR         :
+      printf("\\Ktvirtarr      Transmit Televideo: Right Arrow     \n");
+      break;
+    case  K_TVISUPARR     :
+      printf("\\Ktvisuparr     Transmit Televideo: Shift-Up Arrow  \n");
+      break;
+    case  K_TVISDNARR     :
+      printf("\\Ktvisdnarr     Transmit Televideo: Shift-Down Arrow\n");
+      break;
+    case  K_TVISLFARR     :
+      printf("\\Ktvislfarr     Transmit Televideo: Shift-Left Arrow\n");
+      break;
+    case  K_TVISRTARR     :
+      printf("\\Ktvisrtarr     Transmit Televideo: Shift-Right Arrow\n");
+      break;
+    case K_TVISEND:
+      printf("\\Ktvisend       Transmit Televideo: Send\n");
+      break;
+    case K_TVISSEND:
+      printf("\\Ktvissend      Transmit Televideo: Shift-Send\n");
+      break;
+
+/* HP Function and Edit keys */
+    case  K_HPF01            :
+      printf("\\Khpf01         Transmit Hewlett-Packard: F1       \n");
+      break;
+    case  K_HPF02            :
+      printf("\\Khpf02         Transmit Hewlett-Packard: F2              \n");
+      break;
+    case  K_HPF03            :
+      printf("\\Khpf03         Transmit Hewlett-Packard: F3             \n");
+      break;
+    case  K_HPF04            :
+      printf("\\Khpf04         Transmit Hewlett-Packard: F4              \n");
+      break;
+    case  K_HPF05            :
+      printf("\\Khpf05         Transmit Hewlett-Packard: F5              \n");
+      break;
+    case  K_HPF06            :
+      printf("\\Khpf06         Transmit Hewlett-Packard: F6              \n");
+      break;
+    case  K_HPF07            :
+      printf("\\Khpf07         Transmit Hewlett-Packard: F7              \n");
+      break;
+    case  K_HPF08            :
+      printf("\\Khpf08         Transmit Hewlett-Packard: F8              \n");
+      break;
+    case  K_HPF09            :
+      printf("\\Khpf09         Transmit Hewlett-Packard: F9              \n");
+      break;
+    case  K_HPF10            :
+      printf("\\Khpf10         Transmit Hewlett-Packard: F10             \n");
+      break;
+    case  K_HPF11            :
+      printf("\\Khpf11         Transmit Hewlett-Packard: F11             \n");
+      break;
+    case  K_HPF12            :
+      printf("\\Khpf12         Transmit Hewlett-Packard: F12             \n");
+      break;
+    case  K_HPF13            :
+      printf("\\Khpf13         Transmit Hewlett-Packard: F13             \n");
+      break;
+    case  K_HPF14            :
+      printf("\\Khpf14         Transmit Hewlett-Packard: F14             \n");
+      break;
+    case  K_HPF15            :
+      printf("\\Khpf15         Transmit Hewlett-Packard: F15             \n");
+      break;
+    case  K_HPF16            :
+      printf("\\Khpf16         Transmit Hewlett-Packard: F16             \n");
+      break;
+    case  K_HPRETURN     :
+      printf("\\Khpreturn      Transmit Hewlett-Packard: Return\n");
+      break;
+    case  K_HPENTER          :
+      printf("\\Khpenter       Transmit Hewlett-Packard: Enter (keypad)\n");
+      break;
+    case  K_HPBACKTAB        :
+      printf("\\Khpbacktab     Transmit Hewlett-Packard: Back Tab\n");
+      break;
+        /* Siemens Nixdorf International 97801-5xx kverbs */
+    case K_SNI_DOUBLE_0      :
+        printf("\\Ksni_00          Transmit SNI-97801-5xx: Double-Zero\n");
+        break;
+    case K_SNI_C_DOUBLE_0    :
+        printf(
+"\\Ksni_c_00        Transmit SNI-97801-5xx: Ctrl-Double-Zero\n");
+        break;
+    case K_SNI_C_CE          :
+        printf("\\Ksni_c_ce        Transmit SNI-97801-5xx: Ctrl-CE\n");
+        break;
+    case K_SNI_C_COMPOSE     :
+        printf("\\Ksni_c_compose   Transmit SNI-97801-5xx: Ctrl-Compose\n");
+        break;
+    case K_SNI_C_DELETE_CHAR :
+        printf(
+"\\Ksni_c_del_char  Transmit SNI-97801-5xx: Ctrl-Delete Char\n");
+        break;
+    case K_SNI_C_DELETE_LINE :
+        printf(
+"\\Ksni_c_del_line  Transmit SNI-97801-5xx: Ctrl-Delete Line\n");
+        break;
+    case K_SNI_C_DELETE_WORD :
+        printf(
+"\\Ksni_c_del_word  Transmit SNI-97801-5xx: Ctrl-Delete Word\n");
+        break;
+    case K_SNI_C_CURSOR_DOWN :
+        printf(
+"\\Ksni_c_dnarr     Transmit SNI-97801-5xx: Ctrl-Cursor Down\n");
+        break;
+    case K_SNI_C_ENDMARKE    :
+        printf("\\Ksni_c_endmarke  Transmit SNI-97801-5xx: Ctrl-End Marke\n");
+        break;
+    case K_SNI_C_F01         :
+        printf("\\Ksni_c_f01       Transmit SNI-97801-5xx: Ctrl-F1\n");
+        break;
+    case K_SNI_C_F02         :
+        printf("\\Ksni_c_f02       Transmit SNI-97801-5xx: Ctrl-F2\n");
+        break;
+    case K_SNI_C_F03         :
+        printf("\\Ksni_c_f03       Transmit SNI-97801-5xx: Ctrl-F3\n");
+        break;
+    case K_SNI_C_F04         :
+        printf("\\Ksni_c_f04       Transmit SNI-97801-5xx: Ctrl-F4\n");
+        break;
+    case K_SNI_C_F05         :
+        printf("\\Ksni_c_f05       Transmit SNI-97801-5xx: Ctrl-F5\n");
+        break;
+    case K_SNI_C_F06         :
+        printf("\\Ksni_c_f06       Transmit SNI-97801-5xx: Ctrl-F6\n");
+        break;
+    case K_SNI_C_F07         :
+        printf("\\Ksni_c_f07       Transmit SNI-97801-5xx: Ctrl-F7\n");
+        break;
+    case K_SNI_C_F08         :
+        printf("\\Ksni_c_f08       Transmit SNI-97801-5xx: Ctrl-F8\n");
+        break;
+    case K_SNI_C_F09         :
+        printf("\\Ksni_c_f09       Transmit SNI-97801-5xx: Ctrl-F9\n");
+        break;
+    case K_SNI_C_F10         :
+        printf("\\Ksni_c_f10       Transmit SNI-97801-5xx: Ctrl-F10\n");
+        break;
+    case K_SNI_C_F11         :
+        printf("\\Ksni_c_f11       Transmit SNI-97801-5xx: Ctrl-F11\n");
+        break;
+    case K_SNI_C_F12         :
+        printf("\\Ksni_c_f12       Transmit SNI-97801-5xx: Ctrl-F12\n");
+        break;
+    case K_SNI_C_F13         :
+        printf("\\Ksni_c_f13       Transmit SNI-97801-5xx: Ctrl-F13\n");
+        break;
+    case K_SNI_C_F14         :
+        printf("\\Ksni_c_f14       Transmit SNI-97801-5xx: Ctrl-F14\n");
+        break;
+    case K_SNI_C_F15         :
+        printf("\\Ksni_c_f15       Transmit SNI-97801-5xx: Ctrl-F15\n");
+        break;
+    case K_SNI_C_F16         :
+        printf("\\Ksni_c_f16       Transmit SNI-97801-5xx: Ctrl-F16\n");
+        break;
+    case K_SNI_C_F17         :
+        printf("\\Ksni_c_f17       Transmit SNI-97801-5xx: Ctrl-F17\n");
+        break;
+    case K_SNI_C_F18         :
+        printf("\\Ksni_c_f18       Transmit SNI-97801-5xx: Ctrl-F18\n");
+        break;
+    case K_SNI_C_USER1        :
+        printf(
+"\\Ksni_c_user1     Transmit SNI-97801-5xx: Ctrl-Key below F18\n");
+        break;
+    case K_SNI_C_F19         :
+        printf("\\Ksni_c_f19       Transmit SNI-97801-5xx: Ctrl-F19\n");
+        break;
+    case K_SNI_C_USER2       :
+        printf(
+"\\Ksni_c_user2     Transmit SNI-97801-5xx: Ctrl-Key below F19\n");
+        break;
+    case K_SNI_C_F20         :
+        printf("\\Ksni_c_f20       Transmit SNI-97801-5xx: Ctrl-F20\n");
+        break;
+    case K_SNI_C_USER3       :
+        printf(
+"\\Ksni_c_user3     Transmit SNI-97801-5xx: Ctrl-Key below F20\n");
+        break;
+    case K_SNI_C_F21         :
+        printf("\\Ksni_c_f21       Transmit SNI-97801-5xx: Ctrl-F21\n");
+        break;
+    case K_SNI_C_USER4       :
+        printf(
+"\\Ksni_c_user4     Transmit SNI-97801-5xx: Ctrl-Key below F21\n");
+        break;
+    case K_SNI_C_F22         :
+        printf("\\Ksni_c_f22       Transmit SNI-97801-5xx: Ctrl-F22\n");
+        break;
+    case K_SNI_C_USER5       :
+        printf(
+"\\Ksni_c_user5     Transmit SNI-97801-5xx: Ctrl-Key below F22\n");
+        break;
+    case K_SNI_C_HELP        :
+        printf("\\Ksni_c_help      Transmit SNI-97801-5xx: Ctrl-Help\n");
+        break;
+    case K_SNI_C_HOME        :
+        printf("\\Ksni_c_home      Transmit SNI-97801-5xx: Ctrl-Home\n");
+        break;
+    case K_SNI_C_INSERT_CHAR :
+        printf(
+"\\Ksni_c_ins_char  Transmit SNI-97801-5xx: Ctrl-Insert Char\n");
+        break;
+    case K_SNI_C_INSERT_LINE :
+        printf(
+"\\Ksni_c_ins_line  Transmit SNI-97801-5xx: Ctrl-Insert Line\n");
+        break;
+    case K_SNI_C_INSERT_WORD :
+        printf(
+"\\Ksni_c_ins_word  Transmit SNI-97801-5xx: Ctrl-Insert Word\n");
+        break;
+    case K_SNI_C_LEFT_TAB    :
+        printf("\\Ksni_c_left_tab  Transmit SNI-97801-5xx: Ctrl-Left Tab\n");
+        break;
+    case K_SNI_C_CURSOR_LEFT :
+        printf(
+"\\Ksni_c_lfarr     Transmit SNI-97801-5xx: Ctrl-Cursor Left\n");
+        break;
+    case K_SNI_C_MODE        :
+        printf("\\Ksni_c_mode      Transmit SNI-97801-5xx: Ctrl-Mode\n");
+        break;
+    case K_SNI_C_PAGE        :
+        printf("\\Ksni_c_page      Transmit SNI-97801-5xx: Ctrl-Page\n");
+        break;
+    case K_SNI_C_PRINT       :
+        printf("\\Ksni_c_print     Transmit SNI-97801-5xx: Ctrl-Print\n");
+        break;
+    case K_SNI_C_CURSOR_RIGHT:
+        printf(
+"\\Ksni_c_rtarr     Transmit SNI-97801-5xx: Ctrl-Cursor Right\n");
+        break;
+    case K_SNI_C_SCROLL_DOWN :
+        printf(
+"\\Ksni_c_scroll_dn Transmit SNI-97801-5xx: Ctrl-Scroll Down\n");
+        break;
+    case K_SNI_C_SCROLL_UP   :
+        printf("\\Ksni_c_scroll_up Transmit SNI-97801-5xx: Ctrl-Scroll Up\n");
+        break;
+    case K_SNI_C_START       :
+        printf("\\Ksni_c_start     Transmit SNI-97801-5xx: Ctrl-Start\n");
+        break;
+    case K_SNI_C_CURSOR_UP   :
+        printf("\\Ksni_c_uparr     Transmit SNI-97801-5xx: Ctrl-Cursor Up\n");
+        break;
+    case K_SNI_C_TAB         :
+        printf("\\Ksni_c_tab       Transmit SNI-97801-5xx: Ctrl-Tab\n");
+        break;
+    case K_SNI_CE            :
+        printf("\\Ksni_ce          Transmit SNI-97801-5xx: CE\n");
+        break;
+    case K_SNI_CH_CODE:
+        printf("\\Ksni_ch_code     Toggle SNI-97801-5xx: CH.CODE function.\n");
+        break;
+    case K_SNI_COMPOSE       :
+        printf("\\Ksni_compose     Transmit SNI-97801-5xx: Compose\n");
+        break;
+    case K_SNI_DELETE_CHAR   :
+        printf("\\Ksni_del_char    Transmit SNI-97801-5xx: Delete Char\n");
+        break;
+    case K_SNI_DELETE_LINE   :
+        printf("\\Ksni_del_line    Transmit SNI-97801-5xx: Delete Line\n");
+        break;
+    case K_SNI_DELETE_WORD   :
+        printf("\\Ksni_del_word    Transmit SNI-97801-5xx: Delete Word\n");
+        break;
+    case K_SNI_CURSOR_DOWN   :
+        printf("\\Ksni_dnarr       Transmit SNI-97801-5xx: Cursor Down\n");
+        break;
+    case K_SNI_ENDMARKE      :
+        printf("\\Ksni_endmarke    Transmit SNI-97801-5xx: End Marke\n");
+        break;
+    case K_SNI_F01           :
+        printf("\\Ksni_f01         Transmit SNI-97801-5xx: F1\n");
+        break;
+    case K_SNI_F02           :
+        printf("\\Ksni_f02         Transmit SNI-97801-5xx: F2\n");
+        break;
+    case K_SNI_F03           :
+        printf("\\Ksni_f03         Transmit SNI-97801-5xx: F3\n");
+        break;
+    case K_SNI_F04           :
+        printf("\\Ksni_f04         Transmit SNI-97801-5xx: F4\n");
+        break;
+    case K_SNI_F05           :
+        printf("\\Ksni_f05         Transmit SNI-97801-5xx: F5\n");
+        break;
+    case K_SNI_F06           :
+        printf("\\Ksni_f06         Transmit SNI-97801-5xx: F6\n");
+        break;
+    case K_SNI_F07           :
+        printf("\\Ksni_f07         Transmit SNI-97801-5xx: F7\n");
+        break;
+    case K_SNI_F08           :
+        printf("\\Ksni_f08         Transmit SNI-97801-5xx: F8\n");
+        break;
+    case K_SNI_F09           :
+        printf("\\Ksni_f09         Transmit SNI-97801-5xx: F9\n");
+        break;
+    case K_SNI_F10           :
+        printf("\\Ksni_f10         Transmit SNI-97801-5xx: F10\n");
+        break;
+    case K_SNI_F11           :
+        printf("\\Ksni_f11         Transmit SNI-97801-5xx: F11\n");
+        break;
+    case K_SNI_F12           :
+        printf("\\Ksni_f12         Transmit SNI-97801-5xx: F12\n");
+        break;
+    case K_SNI_F13           :
+        printf("\\Ksni_f13         Transmit SNI-97801-5xx: F13\n");
+        break;
+    case K_SNI_F14           :
+        printf("\\Ksni_f14         Transmit SNI-97801-5xx: F14\n");
+        break;
+    case K_SNI_F15           :
+        printf("\\Ksni_f15         Transmit SNI-97801-5xx: F15\n");
+        break;
+    case K_SNI_F16           :
+        printf("\\Ksni_f16         Transmit SNI-97801-5xx: F16\n");
+        break;
+    case K_SNI_F17           :
+        printf("\\Ksni_f17         Transmit SNI-97801-5xx: F17\n");
+        break;
+    case K_SNI_F18           :
+        printf("\\Ksni_f18         Transmit SNI-97801-5xx: F18\n");
+        break;
+    case K_SNI_USER1          :
+        printf("\\Ksni_user1       Transmit SNI-97801-5xx: Key below F18\n");
+        break;
+    case K_SNI_F19           :
+        printf("\\Ksni_f19         Transmit SNI-97801-5xx: F19\n");
+        break;
+    case K_SNI_USER2          :
+        printf("\\Ksni_user2       Transmit SNI-97801-5xx: Key below F19\n");
+        break;
+    case K_SNI_F20           :
+        printf("\\Ksni_f20         Transmit SNI-97801-5xx: F20\n");
+        break;
+    case K_SNI_USER3          :
+        printf("\\Ksni_user3       Transmit SNI-97801-5xx: Key below F20\n");
+        break;
+    case K_SNI_F21           :
+        printf("\\Ksni_f21         Transmit SNI-97801-5xx: F21\n");
+        break;
+    case K_SNI_USER4          :
+        printf("\\Ksni_user4       Transmit SNI-97801-5xx: Key below F21\n");
+        break;
+    case K_SNI_F22           :
+        printf("\\Ksni_f22         Transmit SNI-97801-5xx: F22\n");
+        break;
+    case K_SNI_USER5          :
+        printf("\\Ksni_user5       Transmit SNI-97801-5xx: Key below F22\n");
+        break;
+    case K_SNI_HELP          :
+        printf("\\Ksni_help        Transmit SNI-97801-5xx: Help\n");
+        break;
+    case K_SNI_HOME          :
+        printf("\\Ksni_home        Transmit SNI-97801-5xx: Home\n");
+        break;
+    case K_SNI_INSERT_CHAR   :
+        printf("\\Ksni_ins_char    Transmit SNI-97801-5xx: Insert Char\n");
+        break;
+    case K_SNI_INSERT_LINE   :
+        printf("\\Ksni_ins_line    Transmit SNI-97801-5xx: Insert Line\n");
+        break;
+    case K_SNI_INSERT_WORD   :
+        printf("\\Ksni_ins_word    Transmit SNI-97801-5xx: Insert Word\n");
+        break;
+    case K_SNI_LEFT_TAB      :
+        printf("\\Ksni_left_tab    Transmit SNI-97801-5xx: Left Tab\n");
+        break;
+    case K_SNI_CURSOR_LEFT   :
+        printf("\\Ksni_lfarr       Transmit SNI-97801-5xx: Cursor Left\n");
+        break;
+    case K_SNI_MODE          :
+        printf("\\Ksni_mode        Transmit SNI-97801-5xx: Mode\n");
+        break;
+    case K_SNI_PAGE          :
+        printf("\\Ksni_page        Transmit SNI-97801-5xx: Page\n");
+        break;
+    case K_SNI_PRINT         :
+        printf("\\Ksni_print       Transmit SNI-97801-5xx: Print\n");
+        break;
+    case K_SNI_CURSOR_RIGHT  :
+        printf("\\Ksni_rtarr       Transmit SNI-97801-5xx: Cursor Right\n");
+        break;
+    case K_SNI_S_DOUBLE_0    :
+        printf(
+"\\Ksni_s_00        Transmit SNI-97801-5xx: Shift-Double-Zero\n");
+        break;
+    case K_SNI_S_CE          :
+        printf("\\Ksni_s_ce        Transmit SNI-97801-5xx: Shift-CE\n");
+        break;
+    case K_SNI_S_COMPOSE     :
+        printf("\\Ksni_s_compose   Transmit SNI-97801-5xx: Shift-Compose\n");
+        break;
+    case K_SNI_S_DELETE_CHAR :
+        printf(
+"\\Ksni_s_del_char  Transmit SNI-97801-5xx: Shift-Delete Char\n");
+        break;
+    case K_SNI_S_DELETE_LINE :
+        printf(
+"\\Ksni_s_del_line  Transmit SNI-97801-5xx: Shift-Delete Line\n");
+        break;
+    case K_SNI_S_DELETE_WORD :
+        printf(
+"\\Ksni_s_del_word  Transmit SNI-97801-5xx: Shift-Delete Word\n");
+        break;
+    case K_SNI_S_CURSOR_DOWN :
+        printf(
+"\\Ksni_s_dnarr     Transmit SNI-97801-5xx: Shift-Cursor Down\n");
+        break;
+    case K_SNI_S_ENDMARKE    :
+        printf("\\Ksni_s_endmarke  Transmit SNI-97801-5xx: Shift-End Marke\n");
+        break;
+    case K_SNI_S_F01         :
+        printf("\\Ksni_s_f01       Transmit SNI-97801-5xx: Shift-F1\n");
+        break;
+    case K_SNI_S_F02         :
+        printf("\\Ksni_s_f02       Transmit SNI-97801-5xx: Shift-F2\n");
+        break;
+    case K_SNI_S_F03         :
+        printf("\\Ksni_s_f03       Transmit SNI-97801-5xx: Shift-F3\n");
+        break;
+    case K_SNI_S_F04         :
+        printf("\\Ksni_s_f04       Transmit SNI-97801-5xx: Shift-F4\n");
+        break;
+    case K_SNI_S_F05         :
+        printf("\\Ksni_s_f05       Transmit SNI-97801-5xx: Shift-F5\n");
+        break;
+    case K_SNI_S_F06         :
+        printf("\\Ksni_s_f06       Transmit SNI-97801-5xx: Shift-F6\n");
+        break;
+    case K_SNI_S_F07         :
+        printf("\\Ksni_s_f07       Transmit SNI-97801-5xx: Shift-F7\n");
+        break;
+    case K_SNI_S_F08         :
+        printf("\\Ksni_s_f08       Transmit SNI-97801-5xx: Shift-F8\n");
+        break;
+    case K_SNI_S_F09         :
+        printf("\\Ksni_s_f09       Transmit SNI-97801-5xx: Shift-F9\n");
+        break;
+    case K_SNI_S_F10         :
+        printf("\\Ksni_s_f10       Transmit SNI-97801-5xx: Shift-F10\n");
+        break;
+    case K_SNI_S_F11         :
+        printf("\\Ksni_s_f11       Transmit SNI-97801-5xx: Shift-F11\n");
+        break;
+    case K_SNI_S_F12         :
+        printf("\\Ksni_s_f12       Transmit SNI-97801-5xx: Shift-F12\n");
+        break;
+    case K_SNI_S_F13         :
+        printf("\\Ksni_s_f13       Transmit SNI-97801-5xx: Shift-F13\n");
+        break;
+    case K_SNI_S_F14         :
+        printf("\\Ksni_s_f14       Transmit SNI-97801-5xx: Shift-F14\n");
+        break;
+    case K_SNI_S_F15         :
+        printf("\\Ksni_s_f15       Transmit SNI-97801-5xx: Shift-F15\n");
+        break;
+    case K_SNI_S_F16         :
+        printf("\\Ksni_s_f16       Transmit SNI-97801-5xx: Shift-F16\n");
+        break;
+    case K_SNI_S_F17         :
+        printf("\\Ksni_s_f17       Transmit SNI-97801-5xx: Shift-F17\n");
+        break;
+    case K_SNI_S_F18         :
+        printf("\\Ksni_s_f18       Transmit SNI-97801-5xx: Shift-F18\n");
+        break;
+    case K_SNI_S_USER1        :
+        printf(
+"\\Ksni_s_user1     Transmit SNI-97801-5xx: Shift-Key below F18\n");
+        break;
+    case K_SNI_S_F19         :
+        printf("\\Ksni_s_f19       Transmit SNI-97801-5xx: Shift-F19\n");
+        break;
+    case K_SNI_S_USER2       :
+        printf(
+"\\Ksni_s_user2     Transmit SNI-97801-5xx: Shift-Key below F19\n");
+        break;
+    case K_SNI_S_F20         :
+        printf("\\Ksni_s_f20       Transmit SNI-97801-5xx: Shift-F20\n");
+        break;
+    case K_SNI_S_USER3       :
+        printf(
+"\\Ksni_s_user3     Transmit SNI-97801-5xx: Shift-Key below F20\n");
+        break;
+    case K_SNI_S_F21         :
+        printf("\\Ksni_s_f21       Transmit SNI-97801-5xx: Shift-F21\n");
+        break;
+    case K_SNI_S_USER4       :
+        printf(
+"\\Ksni_s_user4     Transmit SNI-97801-5xx: Shift-Key below F21\n");
+        break;
+    case K_SNI_S_F22         :
+        printf("\\Ksni_s_f22       Transmit SNI-97801-5xx: Shift-F22\n");
+        break;
+    case K_SNI_S_USER5       :
+        printf(
+"\\Ksni_s_user5     Transmit SNI-97801-5xx: Shift-Key below F22\n");
+        break;
+    case K_SNI_S_HELP        :
+        printf("\\Ksni_s_help      Transmit SNI-97801-5xx: Shift-Help\n");
+        break;
+    case K_SNI_S_HOME        :
+        printf("\\Ksni_s_home      Transmit SNI-97801-5xx: Shift-Home\n");
+        break;
+    case K_SNI_S_INSERT_CHAR :
+        printf(
+"\\Ksni_s_ins_char  Transmit SNI-97801-5xx: Shift-Insert Char\n");
+        break;
+    case K_SNI_S_INSERT_LINE :
+        printf(
+"\\Ksni_s_ins_line  Transmit SNI-97801-5xx: Shift-Insert Line\n");
+        break;
+    case K_SNI_S_INSERT_WORD :
+        printf(
+"\\Ksni_s_ins_word  Transmit SNI-97801-5xx: Shift-Insert Word\n");
+        break;
+    case K_SNI_S_LEFT_TAB    :
+        printf("\\Ksni_s_left_tab  Transmit SNI-97801-5xx: Shift-Left Tab\n");
+        break;
+    case K_SNI_S_CURSOR_LEFT :
+        printf(
+"\\Ksni_s_lfarr     Transmit SNI-97801-5xx: Shift-Cursor Left\n");
+        break;
+    case K_SNI_S_MODE        :
+        printf("\\Ksni_s_mode      Transmit SNI-97801-5xx: Shift-Mode\n");
+        break;
+    case K_SNI_S_PAGE        :
+        printf("\\Ksni_s_page      Transmit SNI-97801-5xx: Shift-Page\n");
+        break;
+    case K_SNI_S_PRINT       :
+        printf("\\Ksni_s_print     Transmit SNI-97801-5xx: Shift-Print\n");
+        break;
+    case K_SNI_S_CURSOR_RIGHT:
+        printf(
+"\\Ksni_s_rtarr     Transmit SNI-97801-5xx: Shift-Cursor Right\n");
+        break;
+    case K_SNI_S_SCROLL_DOWN :
+        printf(
+"\\Ksni_s_scroll_dn Transmit SNI-97801-5xx: Shift-Scroll Down\n");
+        break;
+    case K_SNI_S_SCROLL_UP   :
+        printf("\\Ksni_s_scroll_up Transmit SNI-97801-5xx: Shift-Scroll Up\n");
+        break;
+    case K_SNI_S_START       :
+        printf("\\Ksni_s_start     Transmit SNI-97801-5xx: Shift-Start\n");
+        break;
+    case K_SNI_S_CURSOR_UP   :
+        printf("\\Ksni_s_uparr     Transmit SNI-97801-5xx: Shift-Cursor Up\n");
+        break;
+    case K_SNI_S_TAB         :
+        printf("\\Ksni_s_tab       Transmit SNI-97801-5xx: Shift-Tab\n");
+        break;
+    case K_SNI_SCROLL_DOWN   :
+        printf("\\Ksni_scroll_dn   Transmit SNI-97801-5xx: Scroll Down\n");
+        break;
+    case K_SNI_SCROLL_UP     :
+        printf("\\Ksni_scroll_up   Transmit SNI-97801-5xx: Scroll Up\n");
+        break;
+    case K_SNI_START         :
+        printf("\\Ksni_start       Transmit SNI-97801-5xx: Start\n");
+        break;
+    case K_SNI_TAB           :
+        printf("\\Ksni_tab         Transmit SNI-97801-5xx: Tab\n");
+        break;
+    case K_SNI_CURSOR_UP     :
+        printf("\\Ksni_uparr       Transmit SNI-97801-5xx: Cursor Up\n");
+        break;
+
+    case K_BA80_ATTR:
+        printf("\\Kba80_attr       Transmit BA80: Attr\n");
+        break;
+    case K_BA80_C_KEY:
+        printf("\\Kba80_c_key      Transmit BA80: C\n");
+        break;
+    case K_BA80_CLEAR:
+        printf("\\Kba80_clear      Transmit BA80: Clear\n");
+        break;
+    case K_BA80_CMD:
+        printf("\\Kba80_cmd        Transmit BA80: Cmd\n");
+        break;
+    case K_BA80_COPY:
+        printf("\\Kba80_copy       Transmit BA80: Copy\n");
+        break;
+    case K_BA80_DEL:
+        printf("\\Kba80_del        Transmit BA80: Delete\n");
+        break;
+    case K_BA80_DEL_B:
+        printf("\\Kba80_del_b      Transmit BA80: Delete B\n");
+        break;
+    case K_BA80_DO:
+        printf("\\Kba80_do         Transmit BA80: Do\n");
+        break;
+    case K_BA80_END:
+        printf("\\Kba80_end        Transmit BA80: End\n");
+        break;
+    case K_BA80_ENV:
+        printf("\\Kba80_env        Transmit BA80: Env\n");
+        break;
+    case K_BA80_EOP:
+        printf("\\Kba80_eop        Transmit BA80: EOP\n");
+        break;
+    case K_BA80_ERASE:
+        printf("\\Kba80_erase      Transmit BA80: Erase\n");
+        break;
+    case K_BA80_FMT:
+        printf("\\Kba80_fmt        Transmit BA80: Format\n");
+        break;
+    case K_BA80_HELP:
+        printf("\\Kba80_help       Transmit BA80: Help\n");
+        break;
+    case K_BA80_HOME:
+        printf("\\Kba80_home       Transmit BA80: Home\n");
+        break;
+    case K_BA80_INS:
+        printf("\\Kba80_ins        Transmit BA80: Insert\n");
+        break;
+    case K_BA80_INS_B:
+        printf("\\Kba80_ins_b      Transmit BA80: Insert B\n");
+        break;
+    case K_BA80_MARK:
+        printf("\\Kba80_mark       Transmit BA80: Mark\n");
+        break;
+    case K_BA80_MOVE:
+        printf("\\Kba80_move       Transmit BA80: Move\n");
+        break;
+    case K_BA80_PA01:
+        printf("\\Kba80_pa01       Transmit BA80: PA1\n");
+        break;
+    case K_BA80_PA02:
+        printf("\\Kba80_pa02       Transmit BA80: PA2\n");
+        break;
+    case K_BA80_PA03:
+        printf("\\Kba80_pa03       Transmit BA80: PA3\n");
+        break;
+    case K_BA80_PA04:
+        printf("\\Kba80_pa04       Transmit BA80: PA4\n");
+        break;
+    case K_BA80_PA05:
+        printf("\\Kba80_pa05       Transmit BA80: PA5\n");
+        break;
+    case K_BA80_PA06:
+        printf("\\Kba80_pa06       Transmit BA80: PA6\n");
+        break;
+    case K_BA80_PA07:
+        printf("\\Kba80_pa07       Transmit BA80: PA7\n");
+        break;
+    case K_BA80_PA08:
+        printf("\\Kba80_pa08       Transmit BA80: PA8\n");
+        break;
+    case K_BA80_PA09:
+        printf("\\Kba80_pa09       Transmit BA80: PA9\n");
+        break;
+    case K_BA80_PA10:
+        printf("\\Kba80_pa10       Transmit BA80: PA10\n");
+        break;
+    case K_BA80_PA11:
+        printf("\\Kba80_pa11       Transmit BA80: PA11\n");
+        break;
+    case K_BA80_PA12:
+        printf("\\Kba80_pa12       Transmit BA80: PA12\n");
+        break;
+    case K_BA80_PA13:
+        printf("\\Kba80_pa13       Transmit BA80: PA13\n");
+        break;
+    case K_BA80_PA14:
+        printf("\\Kba80_pa14       Transmit BA80: PA14\n");
+        break;
+    case K_BA80_PA15:
+        printf("\\Kba80_pa15       Transmit BA80: PA15\n");
+        break;
+    case K_BA80_PA16:
+        printf("\\Kba80_pa16       Transmit BA80: PA16\n");
+        break;
+    case K_BA80_PA17:
+        printf("\\Kba80_pa17       Transmit BA80: PA17\n");
+        break;
+    case K_BA80_PA18:
+        printf("\\Kba80_pa18       Transmit BA80: PA18\n");
+        break;
+    case K_BA80_PA19:
+        printf("\\Kba80_pa19       Transmit BA80: PA19\n");
+        break;
+    case K_BA80_PA20:
+        printf("\\Kba80_pa20       Transmit BA80: PA20\n");
+        break;
+    case K_BA80_PA21:
+        printf("\\Kba80_pa21       Transmit BA80: PA21\n");
+        break;
+    case K_BA80_PA22:
+        printf("\\Kba80_pa22       Transmit BA80: PA22\n");
+        break;
+    case K_BA80_PA23:
+        printf("\\Kba80_pa23       Transmit BA80: PA23\n");
+        break;
+    case K_BA80_PA24:
+        printf("\\Kba80_pa24       Transmit BA80: PA24\n");
+        break;
+    case K_BA80_PGDN:
+        printf("\\Kba80_pgdn       Transmit BA80: Page Down\n");
+        break;
+    case K_BA80_PGUP:
+        printf("\\Kba80_pgup       Transmit BA80: Page Up\n");
+        break;
+    case K_BA80_PICK:
+        printf("\\Kba80_pick       Transmit BA80: Pick\n");
+        break;
+    case K_BA80_PRINT:
+        printf("\\Kba80_print      Transmit BA80: Print\n");
+        break;
+    case K_BA80_PUT:
+        printf("\\Kba80_put        Transmit BA80: Put\n");
+        break;
+    case K_BA80_REFRESH:
+        printf("\\Kba80_refresh    Transmit BA80: Refresh \n");
+        break;
+    case K_BA80_RESET:
+        printf("\\Kba80_reset      Transmit BA80: Reset\n");
+        break;
+    case K_BA80_RUBOUT:
+        printf("\\Kba80_rubout     Transmit BA80: Rubout\n");
+        break;
+    case K_BA80_SAVE:
+        printf("\\Kba80_save       Transmit BA80: Save\n");
+        break;
+    case K_BA80_SOFTKEY1:
+        printf("\\Kba80_softkey1   Transmit BA80: Softkey 1\n");
+        break;
+    case K_BA80_SOFTKEY2:
+        printf("\\Kba80_softkey2   Transmit BA80: Softkey 2\n");
+        break;
+    case K_BA80_SOFTKEY3:
+        printf("\\Kba80_softkey3   Transmit BA80: Softkey 3\n");
+        break;
+    case K_BA80_SOFTKEY4:
+        printf("\\Kba80_softkey4   Transmit BA80: Softkey 4\n");
+        break;
+    case K_BA80_SOFTKEY5:
+        printf("\\Kba80_softkey5   Transmit BA80: Softkey 5\n");
+        break;
+    case K_BA80_SOFTKEY6:
+        printf("\\Kba80_softkey6   Transmit BA80: Softkey 6\n");
+        break;
+    case K_BA80_SOFTKEY7:
+        printf("\\Kba80_softkey7   Transmit BA80: Softkey 7\n");
+        break;
+    case K_BA80_SOFTKEY8:
+        printf("\\Kba80_softkey8   Transmit BA80: Softkey 8\n");
+        break;
+    case K_BA80_SOFTKEY9:
+        printf("\\Kba80_softkey9   Transmit BA80: Softkey 9\n");
+        break;
+    case K_BA80_UNDO:
+        printf("\\Kba80_undo       Transmit BA80: Undo\n");
+        break;
+
+        case  K_I31_F01:
+        printf("\\Ki31_f01         Transmit IBM 31xx: F1\n");
+        break;
+       case  K_I31_F02:         
+        printf("\\Ki31_f02         Transmit IBM 31xx: F2\n");
+        break;
+       case  K_I31_F03:         
+        printf("\\Ki31_f03         Transmit IBM 31xx: F3\n");
+        break;
+       case  K_I31_F04:         
+        printf("\\Ki31_f04         Transmit IBM 31xx: F4\n");
+        break;
+       case  K_I31_F05:         
+        printf("\\Ki31_f05         Transmit IBM 31xx: F5\n");
+        break;
+       case  K_I31_F06:         
+        printf("\\Ki31_f06         Transmit IBM 31xx: F6\n");
+        break;
+       case  K_I31_F07:         
+        printf("\\Ki31_f07         Transmit IBM 31xx: F7\n");
+        break;
+       case  K_I31_F08:         
+        printf("\\Ki31_f08         Transmit IBM 31xx: F8\n");
+        break;
+       case  K_I31_F09:         
+        printf("\\Ki31_f09         Transmit IBM 31xx: F9\n");
+        break;
+       case  K_I31_F10:         
+        printf("\\Ki31_f10         Transmit IBM 31xx: F10\n");
+        break;
+       case  K_I31_F11:         
+        printf("\\Ki31_f11         Transmit IBM 31xx: F11\n");
+        break;
+       case  K_I31_F12:         
+        printf("\\Ki31_f12         Transmit IBM 31xx: F12\n");
+        break;
+       case  K_I31_F13:         
+        printf("\\Ki31_f13         Transmit IBM 31xx: F13\n");
+        break;
+       case  K_I31_F14:         
+        printf("\\Ki31_f14         Transmit IBM 31xx: F14\n");
+        break;
+       case  K_I31_F15:         
+        printf("\\Ki31_f15         Transmit IBM 31xx: F15\n");
+        break;
+       case  K_I31_F16:         
+        printf("\\Ki31_f16         Transmit IBM 31xx: F16\n");
+        break;
+       case  K_I31_F17:         
+        printf("\\Ki31_f17         Transmit IBM 31xx: F17\n");
+        break;
+       case  K_I31_F18:         
+        printf("\\Ki31_f18         Transmit IBM 31xx: F18\n");
+        break;
+       case  K_I31_F19:         
+        printf("\\Ki31_f19         Transmit IBM 31xx: F19\n");
+        break;
+       case  K_I31_F20:         
+        printf("\\Ki31_f20         Transmit IBM 31xx: F20\n");
+        break;
+       case  K_I31_F21:         
+        printf("\\Ki31_f21         Transmit IBM 31xx: F21\n");
+        break;
+       case  K_I31_F22:         
+        printf("\\Ki31_f22         Transmit IBM 31xx: F22\n");
+        break;
+       case  K_I31_F23:         
+        printf("\\Ki31_f23         Transmit IBM 31xx: F23\n");
+        break;
+       case  K_I31_F24:         
+        printf("\\Ki31_f24         Transmit IBM 31xx: F24\n");
+        break;
+       case  K_I31_F25:         
+        printf("\\Ki31_f25         Transmit IBM 31xx: F25\n");
+        break;
+       case  K_I31_F26:         
+        printf("\\Ki31_f26         Transmit IBM 31xx: F26\n");
+        break;
+       case  K_I31_F27:         
+        printf("\\Ki31_f27         Transmit IBM 31xx: F27\n");
+        break;
+       case  K_I31_F28:         
+        printf("\\Ki31_f28         Transmit IBM 31xx: F28\n");
+        break;
+       case  K_I31_F29:         
+        printf("\\Ki31_f29         Transmit IBM 31xx: F29\n");
+        break;
+       case  K_I31_F30:         
+        printf("\\Ki31_f30         Transmit IBM 31xx: F30\n");
+        break;
+       case  K_I31_F31:         
+        printf("\\Ki31_f31         Transmit IBM 31xx: F31\n");
+        break;
+       case  K_I31_F32:         
+        printf("\\Ki31_f32         Transmit IBM 31xx: F32\n");
+        break;
+       case  K_I31_F33:         
+        printf("\\Ki31_f33         Transmit IBM 31xx: F33\n");
+        break;
+       case  K_I31_F34:         
+        printf("\\Ki31_f34         Transmit IBM 31xx: F34\n");
+        break;
+       case  K_I31_F35:         
+        printf("\\Ki31_f35         Transmit IBM 31xx: F35\n");
+        break;
+       case  K_I31_F36:         
+        printf("\\Ki31_f36         Transmit IBM 31xx: F36\n");
+        break;
+       case  K_I31_PA1:         
+        printf("\\Ki31_pa1         Transmit IBM 31xx: PA1\n");
+        break;
+       case  K_I31_PA2:         
+        printf("\\Ki31_pa2         Transmit IBM 31xx: PA2\n");
+        break;
+       case  K_I31_PA3:         
+        printf("\\Ki31_pa3         Transmit IBM 31xx: PA3\n");
+        break;
+       case  K_I31_RESET:
+        printf("\\Ki31_reset       Transmit IBM 31xx: Reset\n");
+        break;            
+       case  K_I31_JUMP:        
+        printf("\\Ki31_jump        Transmit IBM 31xx: Jump\n");
+        break;
+       case  K_I31_CLEAR:       
+        printf("\\Ki31_clear       Transmit IBM 31xx: Clear\n");
+        break;
+       case  K_I31_ERASE_EOF:   
+        printf("\\Ki31_erase_eof   Transmit IBM 31xx: Erase to End of Field\n");
+        break;
+       case  K_I31_ERASE_EOP:   
+        printf("\\Ki31_eop         Transmit IBM 31xx: Erase to End of Page\n");
+        break;
+       case  K_I31_ERASE_INP:   
+        printf("\\Ki31_inp         Transmit IBM 31xx: Erase Input Operation\n");
+        break;
+       case  K_I31_INSERT_CHAR: 
+        printf("\\Ki31_ins_char    Transmit IBM 31xx: Insert Character\n");
+        break;
+       case  K_I31_INSERT_SPACE:
+        printf("\\Ki31_ins_space   Transmit IBM 31xx: Insert Space\n");
+        break;
+       case  K_I31_DELETE:      
+        printf("\\Ki31_delete      Transmit IBM 31xx: Delete Character\n");
+        break;
+       case  K_I31_INS_LN:      
+        printf("\\Ki31_ins_line    Transmit IBM 31xx: Insert Line\n");
+        break;
+       case  K_I31_DEL_LN:      
+        printf("\\Ki31_del_ln      Transmit IBM 31xx: Delete Line\n");
+        break;
+       case  K_I31_PRINT_LINE:  
+        printf("\\Ki31_prt_line    Transmit IBM 31xx: Print Line\n");
+        break;
+       case  K_I31_PRINT_MSG:   
+        printf("\\Ki31_prt_msg     Transmit IBM 31xx: Print Message\n");
+        break;
+       case  K_I31_PRINT_SHIFT: 
+        printf("\\Ki31_prt_shift   Transmit IBM 31xx: Print Shift\n");
+        break;
+       case  K_I31_CANCEL:      
+        printf("\\Ki31_cancel      Transmit IBM 31xx: Cancel\n");
+        break;
+       case  K_I31_SEND_LINE:   
+        printf("\\Ki31_send_line   Transmit IBM 31xx: Send Line\n");
+        break;
+       case  K_I31_SEND_MSG:    
+        printf("\\Ki31_send_msg    Transmit IBM 31xx: Send Message\n");
+        break;
+       case  K_I31_SEND_PAGE:   
+        printf("\\Ki31_send_page   Transmit IBM 31xx: Send Page\n");
+        break;
+       case  K_I31_HOME:        
+        printf("\\Ki31_home        Transmit IBM 31xx: Home\n");
+        break;
+       case  K_I31_BACK_TAB:    
+        printf("\\Ki31_back_tab    Transmit IBM 31xx: Back Tab\n");
+        break;
+       case  K_SUN_STOP: 
+        printf("\\Ksunstop         Transmit SUN Console: Stop\n");
+        break;
+       case  K_SUN_AGAIN:
+        printf("\\Ksunagain        Transmit SUN Console: Again\n");
+        break;
+       case  K_SUN_PROPS:
+        printf("\\Ksunprops        Transmit SUN Console: Props\n");
+        break;
+       case  K_SUN_UNDO: 
+        printf("\\Ksunundo         Transmit SUN Console: Undo\n");
+        break;
+       case  K_SUN_FRONT:
+        printf("\\Ksunfront        Transmit SUN Console: Front\n");
+        break;
+       case  K_SUN_COPY: 
+        printf("\\Ksuncopy         Transmit SUN Console: Copy\n");
+        break;
+       case  K_SUN_OPEN: 
+        printf("\\Ksunopen         Transmit SUN Console: Open\n");
+        break;
+       case  K_SUN_PASTE:
+        printf("\\Ksunpaste        Transmit SUN Console: Paste\n");
+        break;
+       case  K_SUN_FIND: 
+        printf("\\Ksunfind         Transmit SUN Console: Find\n");
+        break;
+       case  K_SUN_CUT:  
+        printf("\\Ksuncut          Transmit SUN Console: Cut\n");
+        break;
+       case  K_SUN_HELP: 
+        printf("\\Ksunhelp         Transmit SUN Console: Help\n");
+        break;
+
+       default:
+        printf("No additional help available for this kverb\n");
+  }
+    printf("\n");
+
+    /* This is not the proper way to do it since it doesn't show  */
+    /* all emulations, nor does it show the special modes, but it */
+    /* is better than nothing.                                    */
+
+    printf("Current bindings:\n");
+    found = 0;
+    for (i = 256; i < KMSIZE ; i++) {
+        con_event evt = mapkey(i);
+        if (evt.type != kverb)
+          continue;
+        if ((evt.kverb.id & ~F_KVERB) == xx) {
+            found = 1;
+            printf("  \\%-4d - %s\n",i,keyname(i));
+        }
+    }
+#ifdef OS2MOUSE
+    for ( button = 0 ; button < MMBUTTONMAX ; button++ )
+      for ( event = 0 ; event < MMEVENTSIZE ; event++ )
+        if ( mousemap[button][event].type == kverb ) {
+            if ( (mousemap[button][event].kverb.id & ~F_KVERB) == xx ) {
+                found = 1;
+                printf("  Mouse - %s\n",mousename(button,event));
+            }
+        }
+#endif /* OS2MOUSE */
+
+    if ( !found ) {
+        printf("  (none)\n");
+    }
+    return(0);
+}
+#endif /* NOKVERBS */
+#endif /* OS2 */
+
+#ifndef NOXFER
+/*  D O H R M T  --  Give help about REMOTE command  */
+
+static char *hrset[] = {
+"Syntax:  REMOTE SET parameter value",
+"Example: REMOTE SET FILE TYPE BINARY",
+"  Asks the Kermit server to set the named parameter to the given value.",
+"  Equivalent to typing the corresponding SET command directly to the other",
+"  Kermit if it were in interactive mode.", "" };
+
+int
+dohrmt(xx) int xx; {
+    int x;
+    if (xx == -3) return(hmsga(hmhrmt));
+    if (xx < 0) return(xx);
+    if ((x = cmcfm()) < 0) return(x);
+    switch (xx) {
+
+case XZCPY:
+    return(hmsg("Syntax: REMOTE COPY source destination\n\
+  Asks the Kermit server to copy the source file to destination.\n\
+  Synonym: RCOPY."));
+
+case XZCWD:
+#ifdef NEWFTP
+    return(hmsg("Syntax: REMOTE CD [ name ]\n\
+  Asks the Kermit or FTP server to change its working directory or device.\n\
+  If the device or directory name is omitted, restore the default.\n\
+  Synonym: RCD."));
+#else
+    return(hmsg("Syntax: REMOTE CD [ name ]\n\
+  Asks the Kermit server to change its working directory or device.\n\
+  If the device or directory name is omitted, restore the default.\n\
+  Synonym: RCD."));
+#endif /* NEWFTP */
+
+case XZDEL:
+#ifdef NEWFTP
+    return(hmsg("Syntax: REMOTE DELETE filespec\n\
+  Asks the Kermit or FTP server to delete the named file(s).\n\
+  Synonym: RDEL."));
+#else
+    return(hmsg("Syntax: REMOTE DELETE filespec\n\
+  Asks the Kermit server to delete the named file(s).\n\
+  Synonym: RDEL."));
+#endif /* NEWFTP */
+
+case XZMKD:
+#ifdef NEWFTP
+    return(hmsg("Syntax: REMOTE MKDIR directory-name\n\
+  Asks the Kermit or FTP server to create the named directory.\n\
+  Synonym: RMKDIR."));
+#else
+    return(hmsg("Syntax: REMOTE MKDIR directory-name\n\
+  Asks the Kermit server to create the named directory.\n\
+  Synonym: RMKDIR."));
+#endif /* NEWFTP */
+
+case XZRMD:
+#ifdef NEWFTP
+    return(hmsg("Syntax: REMOTE RMDIR directory-name\n\
+  Asks the Kermit or FTP server to remove the named directory.\n\
+  Synonym: RRMDIR."));
+#else
+    return(hmsg("Syntax: REMOTE RMDIR directory-name\n\
+  Asks the Kermit server to remove the named directory.\n\
+  Synonym: RRMDIR."));
+#endif /* NEWFTP */
+
+case XZDIR:
+#ifdef NEWFTP
+    return(hmsg("Syntax: REMOTE DIRECTORY [ filespec ]\n\
+  Asks the Kermit or FTP server to provide a directory listing of the named\n\
+  file(s) or if no file specification is given, of all files in its current\n\
+  directory.  Synonym: RDIR."));
+#else
+    return(hmsg("Syntax: REMOTE DIRECTORY [ filespec ]\n\
+  Asks the Kermit server to provide a directory listing of the named\n\
+  file(s) or if no file specification is given, of all files in its current\n\
+  directory.  Synonym: RDIR."));
+#endif /* NEWFTP */
+
+case XZHLP:
+#ifdef NEWFTP
+    return(hmsg("Syntax: REMOTE HELP\n\
+  Asks the Kermit or FTP server to list the services it provides.\n\
+  Synonym: RHELP."));
+#else
+    return(hmsg("Syntax: REMOTE HELP\n\
+  Asks the Kermit server to list the services it provides.\n\
+  Synonym: RHELP."));
+#endif /* NEWFTP */
+
+case XZHOS:
+    return(hmsg("Syntax: REMOTE HOST command\n\
+  Sends a command to the other computer in its own command language\n\
+  through the Kermit server that is running on that host.  Synonym: RHOST."));
+
+#ifndef NOFRILLS
+case XZKER:
+    return(hmsg("Syntax: REMOTE KERMIT command\n\
+  Sends a command to the remote Kermit server in its own command language.\n\
+  Synonym: RKERMIT."));
+
+case XZLGI:
+    return(hmsg("Syntax: REMOTE LOGIN user password [ account ]\n\
+  Logs in to a remote Kermit server that requires you login.  Note: RLOGIN\n\
+  is NOT a synonym for REMOTE LOGIN."));
+
+case XZLGO:
+    return(hmsg("Syntax: REMOTE LOGOUT\n\
+  Logs out from a remote Kermit server to which you have previously logged in."
+));
+
+case XZPRI:
+    return(hmsg("Syntax: REMOTE PRINT filespec [ options ]\n\
+  Sends the specified file(s) to the remote Kermit and ask it to have the\n\
+  file printed on the remote system's printer, using any specified options.\n\
+  Synonym: RPRINT."));
+#endif /* NOFRILLS */
+
+case XZREN:
+#ifdef NEWFTP
+    return(hmsg("Syntax: REMOTE RENAME filespec newname\n\
+  Asks the Kermit or FTP server to rename the file.  Synonym: RRENAME."));
+#else
+    return(hmsg("Syntax: REMOTE RENAME filespec newname\n\
+  Asks the Kermit server to rename the file.  Synonym: RRENAME."));
+#endif /* NEWFTP */
+
+case XZSET:
+    return(hmsga(hrset));
+
+case XZSPA:
+    return(hmsg("Syntax: REMOTE SPACE [ name ]\n\
+  Asks the Kermit server to tell you about its disk space on the current\n\
+  disk or directory, or in the one that you name.  Synonym: RSPACE."));
+
+#ifndef NOFRILLS
+case XZTYP:
+#ifdef NEWFTP
+    return(hmsg("Syntax: REMOTE TYPE file\n\
+  Asks the Kermit or FTP server to send the named file to your screen.\n\
+  Synonym: RTYPE."));
+#else
+    return(hmsg("Syntax: REMOTE TYPE file\n\
+  Asks the Kermit server to send the named file(s) to your screen.\n\
+  Synonym: RTYPE."));
+#endif /* NEWFTP */
+
+
+case XZWHO:
+    return(hmsg("Syntax: REMOTE WHO [ name ]\n\
+  Asks the Kermit server to list who's logged in, or to give information\n\
+  about the named user.  Synonym: RWHO."));
+#endif /* NOFRILLS */
+
+#ifndef NOSPL
+case XZQUE:
+    return(hmsg(
+"Syntax: [ REMOTE ] QUERY { KERMIT, SYSTEM, USER } variable-name\n\
+  Asks the Kermit server to send the value of the named variable of the\n\
+  given type, and make it available in the \\v(query) variable.  When the\n\
+  type is KERMIT functions may also be specified as if they were variables."));
+
+case XZASG:
+    return(hmsg(
+"Syntax: REMOTE ASSIGN variable-name [ value ]\n\
+  Assigns the given value to the named global variable on the server.\n\
+  Synonyms: RASG, RASSIGN."));
+#endif /* NOSPL */
+
+case XZPWD:
+    return(hmsg(
+#ifdef NEWFTP
+"Syntax: REMOTE PWD\n\
+  Asks the Kermit server to display its current working directory.\n\
+  Synonym: RPWD."));
+#else
+"Syntax: REMOTE PWD\n\
+  Asks the Kermit or FTP server to display its current working directory.\n\
+  Synonym: RPWD."));
+#endif /* NEWFTP */
+
+case XZXIT:
+#ifdef NEWFTP
+    return(hmsg("Syntax: REMOTE EXIT\n\
+   Asks the Kermit server to exit (without disconnecting), or closes an FTP\n\
+   connection.  Synonym: REXIT, and (for FTP only) BYE, FTP BYE."));
+#else
+    return(hmsg("Syntax: REMOTE EXIT\n\
+  Asks the Kermit server to exit.  Synonym: REXIT."));
+#endif /* NEWFTP */
+
+default:
+    if ((x = cmcfm()) < 0) return(x);
+    printf("?Sorry, no help available - \"%s\"\n",cmdbuf);
+    return(-9);
+    }
+}
+#endif /* NOXFER */
+#endif /* NOHELP */
+#endif /* NOICP */
index bdc5957..5623377 100644 (file)
@@ -3,3 +3,4 @@
 030_fix-if-else.patch
 040_pam-password-prompting.patch
 050_ck_patch.patch
 030_fix-if-else.patch
 040_pam-password-prompting.patch
 050_ck_patch.patch
+060_speeling.patch
index d8d9ddd..1d644cd 100644 (file)
--- a/ckcftp.c
+++ b/ckcftp.c
@@ -8623,7 +8623,7 @@ static char * fhs_mge[] = {             /* MGET */
 #endif /* NOCSETS */
     "  /SERVER-RENAME:text",
     "    Each server source file is to be renamed on the server as indicated",
 #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.",
+    "    immediately after, but only if, it has arrived successfully.",
     "  /SMALLER-THAN:number",
     "    Download only those files smaller than the given number of bytes.",
     "  /TEXT",                          /* /ASCII */
     "  /SMALLER-THAN:number",
     "    Download only those files smaller than the given number of bytes.",
     "  /TEXT",                          /* /ASCII */
index 1290763..2cc29c6 100644 (file)
--- a/ckuus2.c
+++ b/ckuus2.c
@@ -3660,7 +3660,7 @@ static char *hmxydial[] = {
 " ",
 "SET DIAL RETRIES <number>",
 "  How many times to redial each number if the dialing result is busy or no",
 " ",
 "SET DIAL RETRIES <number>",
 "  How many times to redial each number if the dialing result is busy or no",
-"  no answer, until the call is succesfully answered.  The default is 0",
+"  no answer, until the call is successfully answered.  The default is 0",
 "  because automatic redialing is illegal in some countries.",
 " ",
 "SET DIAL INTERVAL <number>",
 "  because automatic redialing is illegal in some countries.",
 " ",
 "SET DIAL INTERVAL <number>",