--- /dev/null
+/* 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) */
--- /dev/null
+#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 */